I have a script that uses ajax to send mail. I have tested it by checking the email that will receive the mail and true enough, the ajax request is successful. I also checked the console window of my Firefox browser and it also shows me a successful message. But my problem here is that instead of the done callback function, the error callback function is fired. You may all wonder why I'm still using the error function instead of fail. The reason for this is because when I tried using the fail function, it doesn't trigger the alertbox that I have set inside it. So what I did is go back and use error function again since at least it triggers the alertbox I made.
Here is the script:
<script type="text/javascript">
var submitButton = $('#submit'); // Variable to cache button element
var alertBox1 = $('.success'); // Variable to cache meter element
var alertBox2 = $('.alert');
var closeButton1 = $('.close1'); // Variable to cache close button element
var closeButton2 = $('.close2'); // Variable to cache close button element
$( function(){
$( '#contactform' ).submit( function(e){
e.preventDefault();
console.log( 'hello' );
var formData = $( this ).serialize();
console.log( formData );
$.ajax({
type: 'POST',
url: 'send.php',
data: formData,
dataType: 'json',
done: function(){
$(submitButton).fadeOut(500); // Fades out submit button when it's clicked
setTimeout(function() { // Delays the next effect
$(alertBox1).fadeIn(500); // Fades in success alert
}, 500);
},
error: function(){
$(submitButton).fadeOut(500); // Fades out submit button when it's clicked
setTimeout(function() { // Delays the next effect
$(alertBox2).fadeIn(500); // Fades in fail alert
}, 500);
}
});
});
$(closeButton1).click(function() { // Initiates the reset function
$(alertBox1).fadeOut(500); // Fades out success message
setTimeout(function() { // Delays the next effect
$('input, textarea').not('input[type=submit]').val(''); // Resets the input fields
$(submitButton).fadeIn(500); // Fades back in the submit button
}, 500);
return false; // This stops the success alert from being removed as we just want to hide it
});
$(closeButton2).click(function() { // Initiates the reset function
$(alertBox2).fadeOut(500); // Fades out success message
setTimeout(function() { // Delays the next effect
$('input, textarea').not('input[type=submit]').val(''); // Resets the input fields
$(submitButton).fadeIn(500); // Fades back in the submit button
}, 500);
return false; // This stops the fail alert from being removed as we just want to hide it
});
});
</script>
What seems to be the one causing this? Just to reiterate, I've tried using fail instead of error callback function since that is one of the answers I found in the Internet and also because I know for a fact that the error function is already deprecated. But because of the reason I mentioned above, I've no choice but to use it.
if you refer the documentation, you cannot use done inside the ajax function as a callback. Either use success or add done at the end of ajax call.
$.ajax({
// url, data etc
success: function() {
//success handler
},
error:function(){
//Error handler
}
});
(OR)
$.ajax({
// ajax related codes
}).done(function(){
//callback
});
Also if you aren't really returning JSON from the server, remove the dataType: 'json', from the ajax call.
Related
I'm stuck in a really bizarre situation here. It's complicated to explain but I'll try my best.
Detailed explanation of the issue:
On every top Nav click (Green donuts/circles), or next button, I must submit the form, if it exists and is valid. If not valid, form.valid() triggers validation errors and return false would stop any further propagation. This setup was working flawlessly until I noticed a strange behavior which isn't very persistence. Form on my 3rd tab, specifically, is quite data heavy. When I hit next button it should practically go thru the same process: check for an existing form, if valid, then submit. Submit calls the POST action method and when post completes it GETs the view for next tab. It works like this 5/10 times but at other times GET executes before the POST, which causes next page to load with incomplete data. When I put breakpoints to debug, I see GET for the next tab executing before POST of the current tab.
UI Explained:
I have a UI with 4 navigation <a> buttons on top - in the center there's a always a form - and at the bottom I have Previous & Next buttons.
Forms are constructed in MVC using Ajax.BeginForm
For each Nav link <a> element on top, I have a JavaScript function
var LoadTabs = function (e, arg) {
// This is to validate a form if one of the top links is clicked and form has incomplete fields...
if (arg !== "prev" && arg !== "next") {
if (!window.ValidateForm(false)) return false;
}
var url = $(this).attr('data'); // this contains link to a GET action method
if (typeof url != "undefined") {
$.ajax(url, { context: { param: arg } }).done(function (data) {
$('#partialViewContainer').html(data);
});
}
}
This function above binds to each top link on page load.
$('.navLinks').on('click', LoadTabs);
My Next & Previous buttons basically trigger the click event i.e. LoadTabs function.
$('button').on('click', function () {
if (this.id === "btnMoveToNextTab") {
if (!window.ValidateForm(true)) return false;
$.ajax({
url: url,
context: { param: 'next' },
method: "GET",
data: data,
success: function(response) {
if (typeof response == 'object') {
if (response.moveAhead) {
MoveNext();
}
} else {
$('#mainView').html(response);
}
ScrollUp(0);
}
});
}
if (this.id === "btnMoveToPreviousTab") {
MoveBack();
}
return false;
});
MoveNext() Implementation is as below:
function MoveNext() {
var listItem = $('#progressbarInd > .active').next('li');
listItem.find('.navLink').trigger('click', ['next']);
ScrollUp(0);
}
The problem is, for some reasons, when Nav Link 3 is active and I hit NEXT button - Instead of posting the form first via form.submit() - the nav 4 gets triggered - hence GET for nav 4 runs before form POST of nav 3.
My ValidateForm method is basically just checking if the form exists and is valid then Submit, else returns false. Its as below:
function ValidateForm(submit) {
var form = $('form');
// if form doesn't exist on the page - return true and continue
if (typeof form[0] === "undefined") return true;
// now check for any validation errors
if (submit) {
if (!$(form).valid()) {
return false;
} else {
$(form).submit();
}
}
else {
return true;
}
return true;
}
My speculation is that form.submit does get triggered as it should be but since submit takes a little longer to finish it continues with the next code block in the button onclick event.
I first thought that this is a server side issue as in the POST I'm saving a big chunk of data with a few loops, and any code block that's process heavy I have that part in
var saveTask = Task.Factory.StartNew(() => ControllerHelper.SomeMethod(db, model)); Task.WaitAll(saveTask);
WaitAll will wait and pause the execution until SomeMethod finishes executing. I'm not sure how can I lock a process in JavaScript and wait for it to finish execution. Because I think If i can somehow lock the form.submit() in ValidateForm until its finished processing .. via a callback method perhaps...
Please if anyone can put me in right direction, I'd greatly appreciate the help. If you need more information please let me know I'd be happy to provide!
Ajax is async, and your forms submit which is using Ajax.BeginForm() is using ajax. What is happening is that when you click your 'Next' button, which triggers the $('button').on('click', function () { code:
You call the ValidateForm() function (and assuming its valid),
your $(form).submit(); line of code starts making a ajax POST
The code progresses to the final return true; line while the ajax
call is executing.
Because the ValidateForm() function returned true, the $.ajax
GET call now starts, but at that point the ajax POST in the
ValidateForm() function may not have finished executing causing
your GET method to return invalid data
You need to change your code so that the GET call is made once the POST method call has completed. And since your using the $.ajax() methods throughout your code, and $.ajax() gives you more flexibility, it seems unnecessary to use Ajax.BeginForm() (and the extra overhead of including the jquery.unbtrusive-ajax.js script). You should also be handling the forms .submit() function (if you do not want the 'Next' button to be a submit button in the form, you could just trigger the .submit() event in the buttons .click() handler)
$(document).on('submit', 'form', function(e) {
e.preventDefault(); // cancel default submit
var form = $(this);
if (!form.valid()) {
return; // will display the validation errors
}
.... // get the relevant urls to the GET and POST methods etc
$.post(postUrl, form.serialize(), function(data) {
.... // not clear if your [HttpPost] method returns anything
}).done(function() {
$.get(getUrl, someData, function(response) {
.... // Update the DOM with the next form?
.... // Re-parse the validator for client side validation
}
}).fail(function() {
.... // code that you might run if the code in the [HttpPost] method fails
});
});
You should also consider returning the appropriate 'next' view in the [HttpPost] method so that you don't then needs to make a second call back to the server to get it.
It is also worth reading the Deferred Object documentation and the use of $.when(), $.then() etc.
Here is the deal: I have a form, that takes quite some time to submit, because I'm waiting for some third party web services. So what I'm trying to achieve is, that after the submit button is clicked, it gets disabled, is assigned a special class and if it takes more than 5 seconds to submit the form, a notice is displayed.
I've came up with this:
$('#register_index_button').click(function(){
$(this).addClass('bt_button_loader');
$(this).val('Please wait');
$(this).attr('disabled', 'disabled');
$('#register_index_form').submit();
//it takes more than 5 seconds, display notice
setTimeout(function() {
$('#notice').html('Still waiting ...');
}, 5000);
});
Everything works fine, except the timeout function. I guess after I submit the form with jQuery, everything else after that is ignored?
Thank you for your help!
Try attaching an event handler on the form for the "submit" event. Put the timeout event handler function.
(https://developer.mozilla.org/en-US/docs/Web/Events/submit)
$('#register_index_form').on('submit', function(){
setTimeout(function() {
$('#notice').html('Still waiting ...');
}, 5000);
});
You should submit after your services get returned, I really don't see any code there that does that, and after you receive your service response, you submit your form.
$('#register_index_button').click(function(){
$(this).addClass('bt_button_loader');
$(this).val('Please wait');
$(this).attr('disabled', 'disabled');
//it takes more than 5 seconds, display notice
setTimeout(function() {
$('#notice').html('Still waiting ...');
}, 5000);
});
Place it when the service is retrieved, an ajax call, in complete method.
$('#register_index_form').submit();
As #gaemaf stated.
$('#register_index_button').click(function(){
$(this).addClass('bt_button_loader');
$(this).val('Please wait');
$(this).attr('disabled', 'disabled');
$('#register_index_form').submit(
//Nested inside of the submit to be executed when submit
setTimeout(function() {
$('#notice').html('Still waiting ...');
}, 5000);
);
});
Another method would be to gather up all of the fields from the form and submit them using an Ajax submit.
That way you can create the 'Please wait' when the ajax is fired and have a confirmation that the form has been received and is being processed. So something like....
$('#register_index_form').submit(function(){
var url = "path/to/your/script.php";
// the script where you handle the form input.
$.ajax({
type: "POST",
url: url,
data: $("#register_index_form").serialize(),
// Gets the forms elements and submits them
timeout: 10000
// How long the Ajax will wait before considering the call to have failed
})
.done(function( data ) {
//Do something ...
});
return false; // avoid to execute the actual submit of the form.
});
I am trying to build an auto-complete UI. There is an input whose on keyup function does an ajax call to server to fetch the most relevant data. But if user types a word which is, say 10 character long, so for each keyup one ajax call is made and my dialogue box refreshes 10 times.
I have tried using abort() for the ajax call. When I do an abort to previous ajax call, the call is not made but still it waits for 10 calls before executing the last one, which makes the user experience very bad.
So is there a way to execute just the current ajax call without any delay from the previous ones?
A part of my code:
var request_autocomplete=jQuery.ajax({});
$('.review_autocomplete').keyup(function() {
request_autocomplete.abort();
request_autocomplete=jQuery.ajax({
// DO something
});
});
OP, there are two parts to this. The first is your abort, which it seems that you already have.
The second is to introduce forgiveness into the process. You want to fire when the user stops typing, and not on every key press.
You need to use both keyUp and keyDown. On keyUp, set a timeout to fire your submit. Give it perhaps 700ms. On KeyDown, clear the timeout.
var request_autocomplete=jQuery.ajax({});
var forgiveness;
// first your AJAX routine as a function
var myServiceCall = function() {
request_autocomplete.abort();
request_autocomplete=jQuery.ajax({
// DO something
}
// keyup
$('.review_autocomplete').keyup(function() {
forgiveness = window.setTimeout(myServiceCall, 700);
});
});
// key down
$('.review_autocomplete').keydown(function() {
window.clearTimeout(forgiveness);
});
});
What this will do is constantly set a timeout to fire every time a key is up, but each time a key is down it will cancel that timeout. This will have the effect of keeping your service call from firing until the user has stopped typing, or paused too long. The end result is that you will wind up aborting a much smaller percentage of your calls.
you can implement the way you asked in your question is preventing for example 3 calls as below :
var calls = 0;
$('.review_autocomplete').keyup(function() {
if (calls >3) {
request_autocomplete.abort();
request_autocomplete=jQuery.ajax({
// DO something
});
calls = 0;
}
calls++;
});
but this way not recommended because when user wants to types sample while user types samp at p ajax call fire up. and when user type l and e nothing happen !
If you are using jquery Autocomplete
you can using
minLenght so you can check current lenght of text box and when user typed at least 3 character then you must call the ajax request.
delay (between last keystroke and ajax call. Usually 2-300ms should do)
and using AjaxQueue
after a quick search about this issue I have found this link that shows another way to prevent multiple ajax calls for autocomplete by using cache
You could use a globalTimeout variable that you reset with setTimeout() and clearTimeout().
var globalTimeout;
$('.review_autocomplete').keydown(function(){
if(globalTimeout)clearTimeout(globalTimeout);
}).keyup(function(){
globalTimeout = setTimeoout(function(){
$.ajax({/* you know the drill */});
}, 10);
});
This way the timeout is cleared whenever your Client pushes a keydown, yet the timeout is set again as soon as the your Client releases a key onkeyup, therefore $.ajax() will only be called if there's no key action, after 10 milliseconds in this case. I admit that this won't stop an $.ajax() call that has already been made, however it probably won't matter because they happen pretty fast, and because this example prevents future $.ajax() calls as long as the Client keeps typing.
Try
var count = {
"start": 0,
// future , by margin of `count.timeout`
"complete": 0,
// if no `keyup` events occur ,
// within span of `count.timeout`
// `request_autocomplete()` is called
// approximately `2` seconds , below ,
// adjustable
"timeout" : 2
};
$('.review_autocomplete')
.focus()
.on("keyup", function (e) {
elem = $(this);
window.clearInterval(window.s);
window.s = null;
var time = function () {
var t = Math.round($.now() / 1000);
count.start = t;
count.complete = t + count.timeout;
};
time();
var request_autocomplete = function () {
return jQuery.ajax({
url: "/echo/json/",
type: "POST",
dataType: "json",
data: {
json: JSON.stringify({
"data": elem.val()
})
}
// DO something
}).done(function (data) {
window.clearInterval(s);
console.log("request complete", data);
$("body").append("<br /><em>" + data.data + "</em>");
elem.val("");
count.start = count.complete = 0;
console.log(count.start, count.complete);
});
};
window.s = setInterval(function () {
if (Math.round($.now() / 1000) > count.complete) {
request_autocomplete();
console.log("requesting data");
};
// increased to `1000` from `501`
}, 1000);
});
jsfiddle http://jsfiddle.net/guest271314/73yrndwy/
I'm making an app where there's loads of products, each with a button. My plan is the user clicks one of the buttons and I have a javascript (jquery) function which starts making an ajax request every second using the id of the button as a parameter to identify the product.
The function I'm planning on using is the 2nd answer here Execute an Ajax request every second
The idea is to check the status of the product (which can change constantly) every second while the user is interested in it.
When the user clicks the button again I want to stop checking this particular product's status but I can't figure out how to do this. In my head I imagine the user might have clicked 3 buttons so there's 3 ajax requests every second happening, each with a different product id. How can I stop the recurring request which has the id of the product the user has clicked stop?
I did something similar recently, where I had an interval running every few seconds and, when some event occurred, I stopped the process altogether. I'm assuming you're using Javascript, so something like the below. You can check "someVar" in the timer call if you wish, up to you...
var someVar = false, intervalId;
$(function () {
// Attach event handler to button
$('#ButtonId').click(function (e) {
if (!someVar) {
e.preventDefault();
someVar = true;
//Start interval
intervalId = setInterval(CheckStatus, 3000);
} else {
// Stop the interval!
clearInterval(intervalId);
someVar = false;
}
});
});
function CheckStatus() {
// I used MVC, but you can use whatever you need to generate the URL
var checkUrl = '#Url.Action("CheckStatus", "SomeController", new { intervalId = "_intervalId_" })'.replace('_intervalId_', intervalId).replace(/&/g, "&");
$.ajax({
url: checkUrl,
type: 'GET',
contentType: 'application/json; charset=utf-8',
success: function (data) {
// do something with the status - data.Status perhaps?
},
error: function () {
//handle error
}
});
}
I have the following code...
$("#myID").click(function(){
//do some ajax requisition here
//make it appears in screen with a fadeIn(300)
});
#myID is an id of one tag
But i need that this function was not called again until the actual execution ends, i tried put many different code before e after the comments but with no success, if you can help me to prevent that second execution!
The fadeIn() don't hold the execution, the code after it was executed while the effect is occurring, can someone help me?
Thanks
You can set a flag that stores the state of whether or not the AJAX function is running:
$(function () {
//set flag to allow AJAX calls
var AJAX_ok = true;
//bind click event handler
$("#myID").click(function(){
//check if it is ok to run an AJAX request right now
if (AJAX_ok === true) {
//if we can run an AJAX request then set the AJAX_ok flag to false so another one does not start
AJAX_ok = false;
//make the AJAX call
$.getJSON('<url>', function (data) {
//now that the callback function has been called, the AJAX call is done, so we re-enable the AJAX_ok flag
AJAX_ok = true;
//make it appears in screen with a fadeIn(300)
//if DATA is valid HTML then...
$(data).css('display', 'none').appendTo('#some-container').fadeIn(300);
});
}
});
});
This will only run one AJAX call from the #myID element's click event handler at a time.
Its possible to kill the previous ajax or you can create an boolean with running, when someone click you set it to true and you have an if(!running){ //do ajax }, on the callback of the ajax you set the running to false
Use a synchronous AJAX call (The default is asynchronous). See this question for details on how to do that.
There are probably 100 better ways, but...
$("#myID").click(function() {
var is_running = $(this).data('running');
if (!is_running)
$(this).data('running', true);
else
return;
/* Do stuff */
$(this).data('running', false);
}
Use callbacks to ensure the order of execution.
$("#myID").click(function(){
$.ajax({
url: 'whatever url you are calling',
success: function(){
alert('ajax done');
$('whatever "it" is').fadeIn(300, function(){
//code place here will not execute until after fade in
alert('fadeIn done');
}
}
})
});