I've seen .when() and .then() used directly with .ajax calls in jquery to delay the execution of a callback function until the ajax is done. What I'm having trouble with is doing the same for functions that are not ajax calls themselves, but contain an ajax function. I've got the following chunk of code:
$(function() {
$('.document').on('click', '.ajax', ajaxFunction);
});
function ajaxFunction(e) {
e.preventDefault();
// ajax request
$.ajax({
async: true,
cache: false,
type: 'post',
url: '/echo/html/',
data: {
html: '<p>This is echoed the response in HTML format</p>',
delay: 1
},
dataType: 'html',
beforeSend: function() {
console.log('Fired prior to the request');
},
success: function(data) {
console.log('Fired when the request is successfull');
$('.document').append(data);
},
complete: function() {
console.log('Fired when the request is complete');
}
});
console.log('hello world!');
}
function defferedFunction(d){
$.when(ajaxFunction(e)).then(alert('hi mom!'))
}
My goal was to fire the alert ('hi mom!') when the contents of the ajaxFunction function were complete, i.e. when the ajax was done and 'hello world!' had logged to the console. However, the alert never comes up.
The problem, so far as I can tell, is that the container function doesn't actually return a promise, and hence the .then() section never fires. How can I modify this code to return a promise when all of the internal code, including the ajax, is finished?
I'd prefer to continue using the .when() / .then() pattern rather than manually including a callback in ajaxFunction.
A fiddle of the above example is here.
You can return a promise
function ajaxFunction(e) {
e.preventDefault();
// ajax request
return $.ajax({ // return promise
async: true,
cache: false,
type: 'post',
url: '/echo/html/',
A couple of things. Like #pXL stated you need to return the promise. Also in your fiddle you need to pass the (d) parameter from your defferedFunction to your ajaxFunction. Finally change your .then
to .done(function(a){});
http://jsfiddle.net/mq4Sj/5/
$(function() {
$('.document').on('click', '.ajax', defferedFunction);
});
function defferedFunction(e){
$.when(ajaxFunction(e)).done(function(d){
alert(d); // ->> response from server.
})
}
I figured out that I can do this by creating a deferred event for the whole function, a deferred event for the non-ajax behavior that I want to capture, resolving the second deferred event after the non-ajax stuff is done, and then using a $.when() to capture when both the deferred object returned by the ajax call is resolved and when the deferred object I created for the non-ajax stuff is done, and then using a .then() to resolve the deferred object for the whole function.
It looks like this, all put together:
$(function() {
$('.document').on('click', '.ajax', defferedFunction);
});
function ajaxFunction(e) {
e.preventDefault();
// ajax request
var ajaxDeferred = $.ajax({
async: true,
cache: false,
type: 'post',
url: '/echo/html/',
data: {
html: '<p>This is echoed the response in HTML format</p>',
delay: 1
},
dataType: 'html',
beforeSend: function() {
console.log('Fired prior to the request')
},
success: function(data) {
console.log('Fired when the request is successfull');
$('.document').append(data);
},
complete: function() {
console.log('Fired when the request is complete');
}
})
var newDeferred = $.Deferred()
var timeoutDeferred = $.Deferred()
setTimeout(function(){
console.log('hello world!')
timeoutDeferred.resolve()
}, 2000)
$.when(timeoutDeferred, ajaxDeferred).then(function(){
newDeferred.resolve()
}
);
return newDeferred;
}
function defferedFunction(e){
$.when(ajaxFunction(e)).done(function(){alert('all done!')})
}
Related
I'm sending ajax call and getting an answer that I need from the first ajax then I want to pass my result to my nested ajax, my var (result) is null in the nested ajax/settimeout fun, can I pass it ? Am I missing something ?
$.ajax({
url: '#Url.Action("getCustomerGuidId", "Document")',
type: 'POST',
cache: false,
data: { "classNum": currentclassNum},
contentType:'json' ,
dataType:'text',
success: function (result) {
alert(result);**-> is fine - not null**.
// a or result is null when I hit the getCurrentDoc- function althought I get the data I need from getCustomerGuidId function
var a = result;-> tried to pass it to a new var..IDK.. I
thought it will help... it didn't.
setTimeout(function () {
$.ajax({
type: "GET",
url: '#Url.Action("getCurrentDoc", "Document")',
contentType:'text',
data: a,-> here it's null
success: function (data) {
}
});
}, 2000);
},
error: function (result) {
alert("fail " + result);
}
});
You can try something like this will help to pass value to nested ajax call
function test(){
var myText = 'Hello all !!';
$.get({
//used the jsonplaceholder url for testing
'url':'https://jsonplaceholder.typicode.com/posts/1',
'method':'GET',
success: function (data) {
//updating value of myText
myText = 'welcome';
$.post({
'url':'https://jsonplaceholder.typicode.com/posts',
'method':'POST',
//data.title is the return value from get request to the post request
'data':{'title':data.title},
'success':function (data) {
alert(data.title +'\n' + myText);//your code here ...
}
});
}
});
}
An old question and you've likely moved on, but there's still no accepted answer.
Your setTimeout takes an anonymous function, so you are losing your binding; if you have to use a Timeout for some reason, you need to add .bind(this) to your setTimeout call (see below)
setTimeout(function () {
$.ajax({
type: "GET",
url: '#Url.Action("getCurrentDoc", "Document")',
contentType:'text',
data: a,
success: function (data) {
}
});
}.bind(this), 2000);
At a guess you're using a Timeout because you want to ensure that your promise (i.e. the first ajax call) is resolving prior to making the nested call.
If that's your intention, you can actually scrap setTimeout completely as you have the nested call in the first ajax success call, which only runs once the promise has been resolved (providing there isn't an error; if so, jQuery would call error rather than success)
Removing setTimeout means you won't lose your binding, and a should still be result (hopefully a is an object, otherwise your second call is also going to experience issues...)
Lastly, after overcoming the binding issue you wouldn't need var a = result; you should be able to pass result directly to your nested ajax call.
Good luck!
In the nested ajax you send a as a param name, not as a param value.
So you can try the following (change param to actual param name which your server expects):
$.ajax({
url: '#Url.Action("getCustomerGuidId", "Document")',
type: 'POST',
cache: false,
data: { "classNum": currentclassNum},
dataType:'text',
success: function (result) {
setTimeout(function () {
$.ajax({
type: "GET",
url: '#Url.Action("getCurrentDoc", "Document")',
data: {param: result},
success: function (data) {
}
});
}, 2000);
},
error: function (result) {
alert("fail " + result);
}
});
In the following code, I want the alerts to come in order (1st call followed by the second), but it keeps coming the other way around. This is causing some variables to become undefined. What is the order of execution when having multiple ajax queries in the same code? How can I change the order of the alerts?
$(document).ready(function () {
function get_det() {
$.ajax({
url: "aa.php",
type: "POST",
success: function (result) {
alert("1st call");
}
});
}
$.ajax({
type: "POST",
contentType: "application/json",
url: "dd.php",
success: function (result) {
initializeMap();
}
});
function initializeMap() {
//other code
calculateAndDisplayRoute();
//other code
function calculateAndDisplayRoute() {
//other code
get_det();
alert("2nd call");
//other code
}
}
});
Ajax is by default Asynchronous meaning there will be no wait for response.
That is why your 2nd call is calling before ajax request.
You can make ajax Syncronuous by setting async: false. Not recommended as it could cause browser hanging.
For Asynchronous process you can use callback function which only call when your request is completed.(Recommended)
In javascript you can do like this(For your code):
function get_det(callback) {//Your asynchronous request.
$.ajax({
url: "aa.php",
type: "POST",
success: function (result) {
alert("1st call");
callback();//invoke when get response
}
});
}
call like this:
get_det(secondFunction);//calling with callback function
function secondFunction()//your callback function
{
alert("2nd Call");
}
The difference in behavior is due to async nature of ajax calls. In your case, you want to perform some code once the call has executed, hence, you need to use callback functions.
Update your code to following
function get_det(callback) {
$.ajax({
url: "aa.php",
type: "POST",
success: function (result) {
alert("1st call");
if(callback) {
callback();
}
}
});
}
function calculateAndDisplayRoute() {
//other code
get_det(function() {
/* this is the place where you need to put code
* that needs to be executed after the ajax has been executed */
alert("2nd call");
});
}
I suggest chaining the promises that $.ajax returns.
$(document).ready(function () {
function get_det() {
return $.ajax({
url: "aa.php",
type: "POST"
}).then(function(result) {
// Do some stuff - you can even modify the result!
// Return the result to the next "then".
return result;
})
}
// Named after the php script you're hitting.
function dd() {
// Return the promise from Ajax so we can chain!
return $.ajax({
type: "POST",
contentType: "application/json",
url: "dd.php"
});
}
function initializeMap() {
// Do stuff before call
return get_det().then(function(getDetResult) {
// Do stuff after AJAX returns..
return {
getDetResult: getDetResult,
mapInitialized: true
};
});
}
// use it!
dd().then(function(result) {
alert('1st call');
// Pass result from dd to initializeMap.
return initializeMap(result);
}).then(function(initMapResult) {
alert('2nd call', initMapResult.mapInitialized);
});
});
I have a function:
function add() {
$.ajax({
type: "POST",
url: "add.php",
async: "false", // Tried both- async: "false/true"
data: {
name: 'Test',
},
success: function(data) {
document.getElementById('id').value = data;
id = document.getElementById('id').value;
alert(id); // alerts here proper value
}
});
}
function testMyFunction() {
add();
// 'id' was set in add function.
id = document.getElementById('id').value;
alert(id); // Here does not alert value but blank(no value)
// This 'id' value is used at other place but here is issue.
}
Calling testMyFunction() function gives above mentioned issue.
What could be a issue?
$.ajax is an asynchronous call and it updates "id" field after if it is completed. Your code checks for its value in function testMyFunction() instantly after the invocation (and before success: function(data) is invoked).
JavaScript is an asynchronous language. In a nutshell, this means that your code should NEVER block: functions should either complete immediately or get called later, i.e. after some input/output operation is complete (e.g. AJAX request).
Edited: BTW, your code does not work because even with async: false the success function is called in the event loop, thus this can occur even after the code that follows synchronous AJAX. If you use async: true, the AJAX will block, but the success function will be called asynchronously in any case.
So to handle data synchronously, you have to work not with success function, but rather with an object that is returned by $.ajax() call:
var xhr = $.ajax({
type: "POST",
async: false,
url: "add.php",
data: {
name: 'Test',
},
});
alert(xhr.responseText); // Alerts result
Thus, you should never use async: false. Instead, better refactor your code to be like this:
function add(callback) {
$.ajax({
type: "POST",
url: "add.php",
data: {
name: 'Test',
},
success: callback
});
}
function testMyFunction() {
add(function(data) {
// This closure will be called AFTER the request is complete.
document.getElementById('id').value = data;
alert(data); // Alerts proper value.
});
}
Basically, this pseudo-code is WRONG:
result1 = action1();
result2 = action2(result1);
result3 = action3(result2);
...and should be written like this:
action1(function(result1) {
action2(result1, function(result2) {
alert(action3(result2));
});
});
I have a nested ajax requests. The first request returns a list with devices, for each device i do another ajax request to fetch more data. When the nested request is a success i'm appending the data to a <table>.
I need some kind of event that tells me when all requests are complete. How can i do this? See my code below
$.ajax({
type: 'GET',
url: '#Url.Content("~/Service/listAllDevices")',
dataType: 'json',
success: function (data) {
$.each(data.devices.device, function (index, value) {
$.ajax({
type: 'GET',
url: '#Url.Content("~/Service/listLokationLabelsForDevice")' + '?uuid=' + value.uuid,
dataType: 'json',
success: function (data3) {
//Append to table
}
});
});
You can use promises and $.when() to see when all your ajax calls have completed like this:
$.ajax({
type: 'GET',
url: '#Url.Content("~/Service/listAllDevices")',
dataType: 'json',
success: function (data) {
var promises = [];
$.each(data.devices.device, function (index, value) {
promises.push($.ajax({
type: 'GET',
url: '#Url.Content("~/Service/listLokationLabelsForDevice")' + '?uuid=' +
value.uuid,
dataType: 'json',
}));
});
$.when.apply($, promises).done(function() {
// all ajax results are done here
// results from each ajax call are in order in
// arguments[0], arguments[1], ...
// you can now append them all to the table
});
}
});
The basic idea is that you collect the returned promise from each ajax call into an array. You then use jQuery's $.when to have jQuery tell you when all those promises are resolved and to collect all the returned results from them and to keep all the data in the order you requested it in. Then, when the .done() callback from $.when() is called, all the data is available and you can process it all at once, in order.
Note, I've also removed the success handler from the inner ajax call since you can process all the results in the .done() handler.
The event you're looking for is ajaxStop.
$(document).on('ajaxStop', function() {
//do something
});
Reference:
- http://api.jquery.com/ajaxstop/
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 9 years ago.
I would like to create a JavaScript function which returns the value of a jQuery AJAX call. I would like something like this.
function checkUserIdExists(userid){
return $.ajax({
url: 'theurl',
type: 'GET',
cache: false,
data: {
userid: userid
},
success: function(data){
return data;
}
});
}
I know I can do this by setting async to false but I would rather not.
You can't return data returned by an AJAX call unless you want to call it synchronously (and you don't – trust me). But what you can return is a promise of a data returned by an AJAX call and you can do it actually in a very elegant way.
(UPDATE:
Please note that currently jQuery Promises are not compatible with the Promises/A+ specification - more info in this answer.)
Basically you can return the return value of your $.ajax(...) call:
function checkUserIdExists(userid){
return $.ajax({
url: 'theurl',
type: 'GET',
cache: false,
data: {
userid: userid
}
});
}
and someone who calls your function can use it like this:
checkUserIdExists(userid).success(function (data) {
// do something with data
});
See this post of mine for a better explanation and demos if you are interested.
you can pass in a callback function:
function checkUserIdExists(userid, callback) {
$.ajax({
...
success: callback
});
}
checkUserIdExists(4, function(data) {
});
With jQuery 1.5, you can use the brand-new $.Deferred feature, which is meant for exactly this.
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.ajax({ url: "example.php" })
.success(function() { alert("success"); })
.error(function() { alert("error"); })
.complete(function() { alert("complete"); });
// perform other work here ...
// Set another completion function for the request above
jqxhr.complete(function(){ alert("second complete"); });
Source
As of jQuery 1.8, the "success", "error" and "complete" callback are deprecated. Instead you should be using "done", "fail" and "always".
So you could have:
function checkUserIdExists(userid, callback) {
return $.ajax({
url: 'theurl',
type: 'GET',
cache: false,
data: {
userid: userid
}
})
.done(callback)
.fail(function(jqXHR, textStatus, errorThrown) {
// Handle error
});
}
checkUserIdExists(2, function(data) {
console.log(data); // Do what you want with the data returned
});
This isn't how JavaScript asynchronous programming was really meant to be done. Instead, use a callback in your success function to call another function to use your data returned from the server.
Tim, the two scenarios are mutually exclusive; an asynchronous operation will not serve any purpose for, nor will it be able to retrieve returned data.
You should look at an event-enabled infrastructure for your ajax calls