Reputation: 3271
I am doing the following ajax call:
def myfunction(var1, var2){
b1. $.ajax({
url: 'some_url2',
type: "POST",
data: {'mydata': var1, 'mydata2': var2},
success: function (data) {
b2. document.getElementById("successMessageAlert").style.display = "none";
},
error: function(xhr, errmsg, err) {
alert('error1 occurred');
b3. }
}
def function1() {
$.ajax({
url: 'some_url',
type: "POST",
data: formData,
success: function (data) {
var aData = JSON.parse(data);
b4. myfunction(getCookie('selected_Id'), aData);
b5. document.getElementById("successMessageAlert").style.display = "block";
b6. document.getElementById("successMessageText").innerHTML = "<strong>Success!</strong> The encoding record was saved successfully.";
}
},
error: function (xhr, errmsg, err) {
alert('error occurred')
}
});
}
I am also using the following piece of code for csrf:
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
The problem is that statements after the myfunction
are getting executed before myfunction
. So, "successMessageAlert" shows up briefly before getting hidden again.
I used some breakpoints (b1-b6). Following is their execution order:
Based on reading several related SO posts, I know that this issue has to do something with asynchronous nature of ajax calls, the beforesend
function and callbacks but I am not able to put 2 and 2 together. Please help.
PS: I need to change the title of the post. But I am not able to describe this issue succinctly.
Upvotes: 4
Views: 1641
Reputation: 46323
In jQuery, ajax calls return a jqXHR object for asynchronous processing. Among other capabilities, it has a .done
function that attaches a callback to receive the ajax result once the request is done. It's very useful to return and use this object as it opens the door for various kinds of continued processing.
As noted in other answers, it's not a great idea to force ajax calls to behave synchronously as that will block all other processing and can result in very poor UX.
You should use that in your code to only manipulate the UI once that happens:
function myfunction(var1, var2){
// I guess the "successMessageAlert" should be here, no?
document.getElementById("successMessageAlert").style.display = "none";
return $.ajax({
url: 'some_url2',
type: "POST",
data: {'mydata': var1, 'mydata2': var2},
/* success: function (data) {
document.getElementById("successMessageAlert").style.display = "none";
},*/ // <- Bring this back if that's really what you wanted...
error: function(xhr, errmsg, err) {
alert('error1 occurred');
}
}
function function1() {
$.ajax({
url: 'some_url',
type: "POST",
data: formData,
success: function (data) {
var aData = JSON.parse(data);
myfunction(getCookie('selected_Id'), aData).done(function () {
document.getElementById("successMessageAlert").style.display = "block";
document.getElementById("successMessageText").innerHTML = "<strong>Success!</strong> The encoding record was saved successfully.";
});
},
error: function (xhr, errmsg, err) {
alert('error occurred')
}
});
}
Upvotes: 1
Reputation: 4621
Actually , the execution flow is absolutely correct. I don't consider it as anything to do with beforeSend
Now you need to understand the nature of the JavaScript ajax call. Ajax Call are asynchronous
in nature.
asynchronous
means whenever a ajax call get executed then JavaScript doesn't wait for call to get completed and moves to next line of code.
For example In your case
After b1
code moved to b3
--> Because JavaScript doesn't wait for call to get complete
Now Question is when will b2
get executed.
It depends on the network traffic, as soon as the ajax call is complete the b2
code will executed.
How to handles these case :
There are two ways
a) I will not suggest this i.e use async:false
as a parameter in ajax call. When this parameter given in ajax call , It tell JavaScript to wait for
b2
and not to proceed to b3
.
Why I don't suggest this
The call is synchronous i.e in case your request take 3 second to complete, then your site will unresponsive for 3 second.
b) Second approach use callback :
This one is bit complicated but is the best approach.
Firstly you need to identify the code which depend on the ajax call completion , you can place all that code inside a function and get it executed once the ajax call completes
Below is the example :
def myfunction(var1, var2 , callback){
$.ajax({
url: 'some_url2',
type: "POST",
data: {'mydata': var1, 'mydata2': var2},
success: function (data) {
document.getElementById("successMessageAlert").style.display = "none";
callback(); //execute the passed function now
},
error: function(xhr, errmsg, err) {
alert('error1 occurred');
}
}
def function1() {
$.ajax({
url: 'some_url',
type: "POST",
data: formData,
success: function (data) {
var aData = JSON.parse(data);
myfunction(getCookie('selected_Id'), aData ,function(){
//Code will get executed after ajax call completes
document.getElementById("successMessageAlert").style.display = "block";
document.getElementById("successMessageText").innerHTML = "<strong>Success!</strong> The encoding record was saved successfully.";
});
}
},
error: function (xhr, errmsg, err) {
alert('error occurred')
}
});
}
Upvotes: 1
Reputation: 319
try using async:false
in you myfunction
ajax call like this
$.ajax({
url: 'some_url2',
type: "POST",
async:false,
data: {'mydata': var1, 'mydata2': var2},
success: function (data) {
document.getElementById("successMessageAlert").style.display = "none";
},
error: function(xhr, errmsg, err) {
alert('error1 occurred');
}
Please mark an answer if it helps
Upvotes: 1