zeppelin zeppelin - 6 months ago 15
Ajax Question

Get second call's response from first call's promise

getAjaxPromise(myUrl, true, myType, myContentType, mySuccessFunction, myFailureFunction, myData, true) .then(function(data)
{
//Do something with the data returned form second Ajax call.
//But data returned here is from first ajax.
});


self.getAjaxPromise = function(url, async, type, contentType, successCallback, errorCallback, data, isSecureCall)
{
if (isSecureCall) {
var tokenPromise = getTokenPromiseFromServer(); //Another Ajax call to get latest token from service
tokenPromise.then(function(tokenData) { //This then runs fine
return $.ajax({
beforeSend: function(request) {
request.setRequestHeader("authKey", tokenData.key);
},
url: url,
async: async,
type: type,
contentType: contentType,
success:
successCallback,
error: errorCallback,
data: JSON.stringify(data)
});
});
} else { //Just one ajax call
return $.ajax({
beforeSend: function(request) {
request.setRequestHeader("authKey" , "anonymous");
},
url: url,
async: async,
type: type,
contentType: contentType,
success: successCallback,
error: errorCallback,
data: JSON.stringify(data)
});
}
};


In the above code, when I write .then() i get the response of first ajax call, I dont need the response of first ajax, instead i want to get the response of the ajax inside the first ajax's then().

How can i achieve that?

P.S: i have edited the question and added the code for reference.

Answer

The reason this is happening is because you're returning the promise from return getTokenPromiseFromServer(). The return statement from the .then callback attached to that promise is not executed until the original ajax call is completed. So your .then handler is actually being attached to the promise from getTokenPromiseFromServer() rather than the nested $.ajax call.

You'll need to so some refactoring of your code. jQuery provides a method to wait for all promises in a list of promises to resolve before executing the callback using $.when https://api.jquery.com/jquery.when/ Depending your needs, the option below may be more appropriate, but this is one way of accomplishing this.

Here's an example:

$.when(promise1, promise2, promise3).done(function (d1, d2, d3) {
    //d1 = data from promise1
    //d2 = data from promise2
    //d3 = data from promise3
});

When you execute your code to get the promise, you could return a list of promises instead and use $.when to wait until all promises are resolved.

You could get away with less refactoring if you don't care about the getTokenPromiseFromServer() externally from getAjaxPromise. In which case, you could manually create a deferred, return that from getAjaxPromise and then within the callback for getTokenPromiseFromServer(), you could manually resolve the deferred like so. Since you're returning your own deferred object, then .then handler is attached to that instead and isn't executed until you manually resolve the deferred (which you do once the nested $.ajax is resolved. Using this approach, you could nest any number of ajax calls, and the behavior would be the same.

if (isSecureCall) {
  var dfd = $.Deferred(); //create deferred
  getTokenPromiseFromServer().then(function(tokenData) {
    $.ajax({
      beforeSend: function(request) {
        request.setRequestHeader("authKey", tokenData.key);
      },
      url: url,
      async: async,
      type: type,
      contentType: contentType,
      success: successCallback, //Success callback runs fine, then() does not
      error: errorCallback, //Error callback runs fine, then() does not
      data: JSON.stringify(data)
    }).then(function( data, textStatus, jqXHR ) {
              dfd.resolve(data); //manually resolve the deferred which executes any callbacks attached to it
            });
  });
  return dfd; //return the deferred, which .then() will attach to
}