0
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.

Rob
  • 14,746
  • 28
  • 47
  • 65
zeppelin
  • 451
  • 1
  • 4
  • 24
  • Please show us (in this question), the code you are actually asking about. The code you currently have in here shows no ajax calls at all. This question needs to stand on it's own, not depend upon looking at code in some other question. – jfriend00 May 12 '16 at 21:27
  • Plus, passing a success and failure function to something that returns a promise is really not the way to design things at all. Use the promise to handle success and failure, not separate callbacks. – jfriend00 May 12 '16 at 21:28
  • @jfriend00 Actually i am posting from mobile & wasnt able to format the code because i cant see the formatting toolbar thatswhy i referred to my previously asked question for code. Still, i have edited and added the code in this question. – zeppelin May 12 '16 at 21:56
  • @jfriend00 i am using success and error callbacks in the code posted above because i am unable to get response of second call's response in then(). Thats why i have asked the question. If i was able to use then() i wouldnt have used the callbacks. They are there because of i cant seem to get second promise respinse in then(). – zeppelin May 12 '16 at 21:58
  • Please look at the answer I posted as it shows the proper way to use nested promises and return the result of the inner promise back to the resulting `.then()` handler. You do not want to create the extra deferred as suggested in other answers as this is a promise anti-pattern and creates error handling problems (see explanation in my answer). – jfriend00 May 13 '16 at 00:49

3 Answers3

1

To make the .then() work on the outer function, you have to return the top level promise from within that function like this:

self.getAjaxPromise = function (url, async, type, contentType, data, isSecureCall) {
    if (isSecureCall) {
        // return the outer promise from the function so .then() will work
        return getTokenPromiseFromServer().then(function (tokenData) { //This then runs fine
            // return this ajax call to chain it to the previous promise
            return $.ajax({
                beforeSend: function (request) {
                    request.setRequestHeader("authKey", tokenData.key);
                },
                url: url,
                async: async,
                type: type,
                contentType: contentType,
                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,
            data: JSON.stringify(data)
        });
    }
};

Then, you can just call it like this and all results will be returned back in the .then() handler and any errors will propagate all the way back:

 xxx.getAjaxPromise(...).then(function(result) {
     // sucessfull result here
 }, function(err) {
     // error here
 });

Creating the extra promise or deferred, as suggested by another answer is consider a promise anti-pattern as it is entirely unnecessary and often creates error handling problems. Instead, you can just return the promise you already have and, when you have a nested promise, you can return it from within the .then() handler and it will automatically be chained to the first promise, and will control the eventual result of the promise. This will allow your outer .then() handler to work and get the right result.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • +1 for teaching me something. Strangely enough, in the poster's original code on another question (before he added slightly different code in this question), he was returning the top-level promise and the data argument in the final `then` handler was from the top level promise and not the nested one. However, my jsfiddle tests show this working perfectly. – Joel May 13 '16 at 14:50
  • @Joel - Your tests show what working correctly, the OP's original code or my suggested code? – jfriend00 May 13 '16 at 14:57
  • neither, I simply created a contrived example of nested promises and verified that everything executed in the expected order and the data for each callback flowed correctly. – Joel May 13 '16 at 15:06
0

I am not familiar with that method but why don't you use a simple jQuery Ajax call inside a jQuery Ajax call

$.ajax({//params)}.done(() => {   // other ajax  call.     
     $.ajax({  //params}).done((result) => {//target code
                                           }); 
})
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
locomain
  • 185
  • 1
  • 15
  • Only if it were that easy. I have a nested ajax call and need to call a service everytime before the actual ajax is initiated. And these nested ajaxs are in a single function which i call from everywhere. How can i do that in my existing scenario. I cant write both these ajax calls everywhere. – zeppelin May 12 '16 at 22:02
0

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
}

EDIT since people keep downvoting this answer

As @jfriend00 pointed out in his answer, this is considered a promise anti-pattern and should be avoided because it can cause problems in more complex scenarios. Thank you to him for correcting my understanding of promises. Please see his answer for additional details.

Instead, the promises can be chained by simply returning the top-level promise. and calling .then on the returned promise, rather than manually creating a deferred and resolving it.

Joel
  • 2,227
  • 1
  • 17
  • 23
  • 1
    This type of answer is considered a [promise anti-pattern](https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns) and is both undesirable and unnecessary. Instead, you should just return the outer promise from the main function and return the inner promise from within the `.then()` handler. Besides extra, unnecessary code, this anti-pattern also typically creates error handling problems which your code has.If there's an error on the inner ajax call or on the outer `getTokePromiseFromServer()` promise, both of those errors will be silently eaten and not returned from the function. – jfriend00 May 13 '16 at 00:46