Return result from nested asynchronous ajax call - javascript

I need to return the data from an nested ajax call but also need the ajax call to stay asynchronous.
I found some related questions but can't get it to work in the situation below. I assume returnData is being returned before the ajax call is done, but I can't find an solution.
function makeRequest(command, postData){
var returnData;
$.ajax({
url: 'call.php?command='+command,
data: postData,
type: 'POST'
}).done(function(data){
returnData = data;
});
return returnData;
}

Yes since this call is async returnData is returned immediately. If you need to use returndata pass it to a function in the callback
function makeRequest(command, postData, functionToCallAfterAjax){
var returnData;
$.ajax({
url: 'call.php?command='+command,
data: postData,
type: 'POST'
}).done(function(data){
functionToCallAfterAjax(data);
});
}
Of course you could pass the function to call as a parameter.
This means that if your code was meant to do:
var returnedData = makeRequest(command, postData);
anotherFunction(returnedData);
you should do simply (using the code above)
makeRequest(command, postData, anotherFunction);
and everything will work

You can't. Asynchronous events don't work like that.
The HTTP request is sent, then the function that triggers it continues immediately. The callback won't be fired until the HTTP response has arrived, but which time the calling function will have ended.
You must have your callback (the function you are passing to done()) perform whatever further processing is needed.

You're returning the value of returnData before the .done() function has run. Correct your code by passing the received data to a function for processing:
function makeRequest(command, postData){
$.ajax({
url: 'call.php?command='+command,
data: postData,
type: 'POST'
}).done(function(data){
HandleCallBack(data);
});
}

Related

Pass success callback function with arguments to another function that performs AJAX call

I'm new to javascript and trying to understand if following thing is possible:
Let's say I use following ajax request construction in several places in my code (with different success callback functions - in this example only handleSuccessCallback()) and different url and data request param:
jQuery.ajax({
type: 'GET',
url: loadUrl,
data: data,
error: errorCallback,
success: function(response) {
this.handleSuccessCallback(response);
}
});
function handleSuccessCallback(response) {
Do something with response here...
}
I wanted to refactor this code in such way, that I don't need to create construction above each time I need to send request. I wanted to create a function in my utils class that will take url, request data and error/success callback. Something like this:
function sendAjaxRequest(url, data, errorCallback, successCallback)
jQuery.ajax({
type: 'GET',
url: url,
data: data,
error: errorCallback,
success: successCallback
});
}
Then, I wanted to call this function several times passing different arguments from my main script.
In my main code:
var url = "https://some url";
var data = {};
var errorCallback = handleErrorCallback();
var successCallback = handleSuccessCallback(); // ??? This function requires `response` argument being passed, how it can be done?
utils.sendAjaxRequest(url, data, errorCallback, successCallback);
function handleSuccessCallback(response) {
Do something with response here...
}
function handleErrorCallback() {
Do something with error here...
}
However, what I don't understanding is the following:
how can I pass success callback function (handleSuccessCallback(response)) to the sendAjaxRequest() function, if my handleSuccessCallback(response) needs params which is result of the success ajax callback itself(response)?
How can I pass this response param to handleSuccessCallback() when passing it to sendAjaxRequest() if I don't know yet what will be the response from ajax call?
When you want to call:
function sendAjaxRequest(url, data, errorCallback, successCallback)
You just need to give names of functions for errorCallback and successCallback. You are passing function references, so they can be called by other code. The params are provided at the point where those functions are called, like in your original example:
success: function(response) {
this.handleSuccessCallback(response);
}
Here the success function as defined in ajax with first parameter as response, so you have an anonymous function here with the first parameter as response.
So you just need to define your functions to match what they will be when they get called by ajax, e.g.:
var firstSuccessCallback = function(response) {
//do something;
}
var firstErrorCallback = function(error) {
//do something;
}
you can do:
sendAjaxRequest(url, data, firstErrorCallback, firstSuccessCallback)

generalizing ajax call into function

I'm trying to attempt to generalize my ajax calls into a function as follows. I have not done this before and am not sure sure if I'm doing it correctly.
<script>
$(document).ready(function(){
var reg_no=$("#reg_no").val();
reg_no=reg_no.trim();
if(reg_no!==""){
//populate fields
data={reg_no:reg_no,func:"getSupplierDetails"};
success_function="updateFormFields";
ajax_call(data,success_function);
}
});
function ajax_call(data,success_function){
$.ajax({
type:"POST",
url:"../control/supplier-c.php",
dataType:"json",
data:data,
success:function(data){
success_function(data); //variable function works??
}
});
}
function updateFormFields(data){
//some code here to handle data array
}
</script>
What I'm trying to do here is avoid rewriting the whole ajax code by passing the data array and the function to be executed on success. What I'm not sure is the use of variable functions as i have done.
A note to be made is that the whole thing works for an ajax call if updateFormFields() code was moved into the success handler in the ajax call and the ajax_call() was not defined as a seperate function but implemented right after the comment "populate fields". I just have no experience in trying it this way and I need to know if this is possible or not.
Thank You
In Javascript, functions are first class objects, meaning you can pass them around as parameters.
function json_post(url, data, success_function, error_function) {
$.ajax({
type:"POST",
url:url,
dataType:"json",
data:data
}).then(success_function, error_function);
}
Then you can call it as
json_post("../control/supplier-c.php", { data: "data" }, function (res) {
console.log('Ajax req successful');
console.log(res);
}, function (res) {
console.log('Error in ajax req');
console.log(res);
});
In your case, you can do:
ajax_call(data, updateFormFields);
and it should work as expected.
There's no need to wrap the success function, you can just apply apply it directly.
function ajax_call(data, success_function) {
$.ajax({
...
success: success_function
});
}
An even better idea is to avoid the legacy success and error callbacks and instead return the jQuery promise. You can use standard promise methods .then() and `.
function ajax_call(data) {
return $.ajax({
...
});
}
ajax_call()
.then(function(data) {
// this runs if it succeeds
})
.fail(function(err) {
// this runs if it failed
});
Promises have a huge benefit to being chain-able, making the code flatter, avoiding the nest of "christmas tree callbacks".
I would recommend checking success_function as well as failure_function to handle server response (XHR) errors also.
function success_function(){
//code to handle success callback
}
function error_function(){
//code to handle failure callback
}
function ajax_call(data, success_function, error_function) {
if (typeof success_function === 'function' && typeof error_function === 'function') {
$.ajax({
type: "POST",
url: "../control/supplier-c.php",
dataType: "json",
data: data,
}).then(success_function).fail(error_function);
}
}

Ajax call with nested ajax calls in for each

I'm experiencing the following problem.
I have the following nested / foreach loops ajax call structure:
var children = [];
$.fn.ajaxHelper.loadAjax({
url: someUrlReturningJsonOfChildren,
cache: true,
callback: function(options) {
var json = options.json;
$.each(json, function (i) {
// get the details of this child
$.fn.ajaxHelper.loadAjax({
url: urlForDetailsUsingId,
cache: true,
callback: function(options) {
var json = options.json;
children[i] = json;
}
});
}
}
});
// want to do something with (newly filled) children here
As you can imagine, I'm running into the trouble that the ajax calls are asynchronous (duh), but I want to do something with the children array only when all the ajax calls are done. Otherwise I'm obviously dealing with an incomplete array.
I have been looking at some jQuery solutions such as Deferred objects (using $.when().then() and such), but that would only solve the problem if I would not have the foreach-loop (as far as I can tell).
Also, changing the REST API (where the ajax calls are going) is not an option unfortunately, due to specified requirements regarding the API.
Ok, so without further ado: can anyone of you geniuses help me with this? :-)
ajax is asynchronous by default but you can turn it off. Here goes the API on how to do it
https://api.jquery.com/jQuery.ajax/
heres a little demp
$.ajax({
url: my_url.php,
type: "POST",
async: false,
dataType: 'json'
});
Or just make your next ajax call in a success function (Recommended)
function testAjax(handleData) {
$.ajax({
url:"getvalue.php",
success:function(data) {
//next ajax call here
}
});
}
You must run ajax query when previous query is completed with success (in jQuery onSuccess callback)
I had a smiler issue... below is a simplified version of my solution.
Step one: Declare global variables.
var results1,
results2,
[resultsN];
Step two: Make a function that accepts the results of each AJAX call as parameters.
function foo(results1, results2, [resultsN]) {
if (results1, results2, [resultsN]) {
//... do whatever you want with all of your results
}
}
Step three: Call all of the AJAX functions, set results to global variables, and call function foo for each.
function ajax() {
//AJAX call 1
$.ajax({
type: 'POST',
url: //URL,
success: function (data, textStatus, jqXHR) {
results1 = data;
},
dataType: 'json',
complete: function () {
foo(results1, results2);
}
});
//AJAX call 2
$.ajax({
type: 'POST',
url: //URL,
success: function (data, textStatus, jqXHR) {
results2 = data;
},
dataType: 'json',
complete: function () {
foo(results1, results2);
}
});
};
This method has the advantage of running as fast as the longest AJAX call takes. If you simply nest AJAX queries in the complete event then you will have to wait for each AJAX call to complete before moving to the next one...

waiting for an ajax reply

I have a javascript function called GetRequest() that calls the server with $.ajax() and receives a json string:
function GetRequest(ThePage) {
RequestedPage = parseInt(ThePageNumber,10);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "../Pages/MyPage.aspx/GetPage",
data: "{'ThePage':'" + ThePageNumber + "'}",
dataType: "json",
success: function (msg) {
var data = msg.hasOwnProperty("d") ? msg.d : msg;
OnSucessCallBack(data);
},
error: function (xhr, status, error) {
alert(xhr.statusText);
}
});
};
I have a function called ShowData() that calls GetRequest() and must wait until GetRequest receives its data before continuing.
function ShowData() {
//some code that determines the page number
GetRequest(ThePageNumber);
//wait until the data is in
};
I use GetRequest in several places so I can't use its success function in the context of ShowData.
How do I make my function ShowData pause its execution until GetRequest is finished? I thought of changing the OnSuccessCallBack function and determine which function initially called GetRequest() but I'm not sure on how to best do this.
Thanks for your suggestions.
add a function pass-in to GetRequest like so:
function GetRequest(pageNumber, successCallback){
//I admit this isn't "elegant" but it's most assuredly readable
var callback;
if (successCallback == null) {
callback = //default callback definition here
} else {
callback = successCallback;
}
//do everything else the same here
//except use the callback defined above
}
This gives you the flexibility to add in a separate callback handler for the onsuccess
Alternately, do the same as above, but use the "onComplete" handler unless you need the data specifically on the return (it doesn't appear as tho you do).
I'm going to strenuously suggest that you do use callbacks for asynchronous code instead of trying to shoehorn in sync requests. It's much better to just adopt a coding style that revolves around async requests when working in javascript, especially where you're already doing AJAX (which is by definition intended to be async).
Pass async:false along with the ajax options..
$.ajax({
type: "POST",
async:false,
.
.
.
});
You can make your call only synchronous by using ajax prefilters:
function ShowData() {
//some code that determines the page number
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.async = false;
});
GetRequest(ThePageNumber);
//wait until the data is in
};

javascript & jQuery scope question

I have the following method:
function priceRange(FESTIVALID){
jQuery.ajax({
url : '/actions/festheads.cfc?method=getPriceRangeByGUID',
type : 'POST',
data : 'FESTIVALID='+FESTIVALID,
dataType: 'json',
success : function(data) {
console.info("AJAX:qPrices",data.MINPRICE);
formatedPriceRange = '$ '+data.MINPRICE;
console.info("AJAX:formatedPriceRange", formatedPriceRange);
}//success
});//ajax;
//
return formatedPriceRange;
};
The second console.info correctly displays the formatedPriceRange,
but outside the function is undefined.
how can I access this variable out side the priceRange function?
Thanks
It's normal, that's how AJAX works. It's asynchronous, meaning that the jQuery.ajax function returns immediately and in this case formatedPriceRange hasn't yet been assigned a value and once the server responds (which can be for example 10 seconds later), the success callback is invoked and the variable is assigned a value.
So always consume the results of your AJAX requests inside the success callback function.
You also have the possibility to pass the async: false option to your jQuery.ajax call which will perform a synchronous request to the server and block until the result is retrieved. Obviously this will lead to your browser freezing during the execution of the request. So it would no longer be AJAX (Asynchronous Javascript And Xml) but SJAX (Synchronous Javascript and Xml).
You have to make sure that the AJAX request finishes before you access the price range data.
You need to expose the price range data outside the scope of the success function.
Here's how you can do it:
function priceRange(FESTIVALID, callback) {
jQuery.ajax({
url: '/actions/festheads.cfc?method=getPriceRangeByGUID',
type: 'POST',
data: 'FESTIVALID=' + FESTIVALID,
dataType: 'json',
success: function(data) {
console.info("AJAX:qPrices", data.MINPRICE);
formatedPriceRange = '$ ' + data.MINPRICE;
console.info("AJAX:formatedPriceRange", formatedPriceRange);
callback.call(this, formatedPriceRange);
} //success
}); //ajax;
}
var myFestivalID = 1;
priceRange(myFestivalID, function(priceRange) {
// this code runs when the ajax call is complete
alert('The formatted price range is:' + priceRange);
});
how can I access this variable out
side the priceRange function?
Like Darin said, you have to use your results in the success callback function.
Assuming you're using your current function like this:
var range = priceRange(festivalId);
// ... doing stuff with range variable
You'll want reorganize your code so that anything you do with the range variable stems from the success callback. For example, you can create a function to handle updating the UI with the new range:
function handleRangeVariabe(range) {
/// ... do stuff with range variable
}
Call it from success:
success: function(data) {
console.info("AJAX:qPrices",data.MINPRICE);
formatedPriceRange = '$ '+data.MINPRICE;
console.info("AJAX:formatedPriceRange", formatedPriceRange);
handleRangeVariable(formatedPriceRange);
}
Flower the steps of sample Code:
//declare function
function priceRange(FESTIVALID, functionCallBack){
//1º step
jQuery.ajax({
url : '/actions/festheads.cfc?method=getPriceRangeByGUID',
type : 'POST',
data : 'FESTIVALID='+FESTIVALID,
dataType: 'json',
success : function(data) {
//3º step, because this function will only trigger when server responds to request
//handle data in other function
functionCallBack(data);
}//success
});//ajax;
//more code
//2º step
//no return value, because this method no know when the data will return of server
//return formatedPriceRange;
};
var formatedPriceRange;
//using function
princeRange(1 , function(data){
console.info("AJAX:qPrices",data.MINPRICE);
formatedPriceRange = '$ '+data.MINPRICE;
console.info("AJAX:formatedPriceRange", formatedPriceRange);
});

Categories

Resources