1

I have two ajax call that cannot be done in one call. When the first ajax call starts the second ajax call can start immediately or whenever the user presses a send button. If the second ajax call starts he has to wait for the response of the first ajax call because he needs data from it.

How can I achieve that the second ajax call sends his request only after the first ajax call's response has been arrived?

  • Is there another way than setTimeout?
  • Can I register a listener for ajax call 2 on ajax call 1 somehow?

My code would be:

var xhrUploadComplete = false;

// ajax call 1
$.ajax({
url: url,
type: "POST",
data: formdata,
processData: false,
contentType: false,
complete: function(response) {
    var returnedResponse = JSON.parse(response.responseText);
    xhrUploadComplete = true;
}
});

// ajax call 2
if (xhrUploadComplete) {
  $.ajax({
  url: url2,
  type: "POST",
  data: formdata2,
  processData: false,
  contentType: false,
  complete: function(response) {
    ...
  }
  });
}

Edit: The second ajax call cannot be posted in done() or complete() of the first call, because it depends on the users choice to send the final form. The purpose of this two step process is to send an image to the server just after the user had inserted it to an input type=file.

Edit: In know that I cannot the the if(..) because this is an async call. I wrote it to make clear what I need to do. I think I need something like a future in Java.

Michael
  • 32,527
  • 49
  • 210
  • 370
  • 1
    Don't you already have registered a listener for the result of the first ajax call? Please show us your code. – Bergi Oct 01 '13 at 20:27
  • @Bergi I posted the code – Michael Oct 01 '13 at 20:41
  • "If the second ajax call starts he has to wait for the response of the first ajax" => this doesn't make sense, if it has to wait then it cannot start... – Christophe Oct 01 '13 at 21:11
  • @Christophe The second call has to wait until the first call has been completed but cannot start before the user has clicked! – Michael Oct 01 '13 at 21:13

1 Answers1

6

xhrUploadComplete will be set to true asynchronously (in the future, when the request has finished) so your if-condition (that is evaluated right after the request is started) will never be fulfilled. You cannot simply return (or set) a value from an ajax call. Instead, move the code that waits for the results into the handler that would have set/returned the variable:

$.ajax({
    url: url,
    type: "POST",
    data: formdata,
    processData: false,
    contentType: false,
    complete: function(response) {
        var returnedResponse = JSON.parse(response.responseText);
        $.ajax({
            url: url2,
            type: "POST",
            data: formdata2,
            processData: false,
            contentType: false,
            complete: function(response) {
                …
            }
        });
    }
});

With the Promise pattern you can compose those even more elegantly:

$.ajax({
    url: url,
    type: "POST",
    data: formdata,
    processData: false,
    contentType: false
}).then(function(response) {
    var returnedResponse = JSON.parse(response.responseText);
    return $.ajax({
        url: url2,
        type: "POST",
        data: formdata2,
        processData: false,
        contentType: false
    });
}).done(function(response) {
    // result of the last request
    …
}, function(error) {
   // either of them failed
});

Maybe you need also need this:

var ajax1 = $.ajax({
    url: url, …
}).then(function(response) {
    return JSON.parse(response.responseText);
});
$(user).on("decision", function(e) { // whatever :-)
    // as soon as ajax1 will be or has already finished
    ajax1.then(function(response1) {
        // schedule ajax2
        return $.ajax({
             url: url2, …
        })
    }).done(function(response) {
        // result of the last request
        …
    }, function(error) {
        // either of them failed
    });
});
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I cannot do the second ajax request in done() or complete() because the user decides when to send the final form. See the update of my question. – Michael Oct 01 '13 at 20:55
  • Then add the fire it from from the user's decision-handler? With the promise pattern (see my edit) you can always access the value by calling `then`/`done`, regardless whether it is available now or in the future. – Bergi Oct 01 '13 at 20:59
  • This is not what I need because the user has to decide on a click event when the second ajax call is started. The second call then starts only after the first has been finished, but only after the user has clicked. – Michael Oct 01 '13 at 21:01
  • I think it is, check my latest revision. – Bergi Oct 01 '13 at 21:06
  • Nice but why do I need the first then? What is the difference between done() and complete()? – Michael Oct 01 '13 at 21:07
  • 1
    The first `then` is called on the promise that yields the xhr result, and returns a promise that yields the parsed object by transforming the result. You don't need that `then` and could do the transformation in the other `then` as well, but it won't be executed right away then but only (every time) when the user clicks the button (and `ajax1` has been resolved). – Bergi Oct 01 '13 at 21:26
  • I did not get it all. Please rephrase what the first then mean and which one I can ignore? – Michael Oct 01 '13 at 21:29
  • Oops, I didn't notice you used `complete` instead of `done`. Then [`.always`](http://api.jquery.com/deferred.always/) might have been more appropriate than [`.done`](http://api.jquery.com/deferred.done/). Apart from that behavioural difference, `complete/success/error` are options on an ajax config object, while `always/done/fail` are promise methods to register listeners even after the request has been started. – Bergi Oct 01 '13 at 21:30
  • Okay, so what does the second then on ajax1 do? Is it like "is the value now available?" – Michael Oct 01 '13 at 21:32
  • @confile: I thought you were referring to my last code snippet? There are only two `then` calls. I wanted to say that using two of them is more convenient, but instead of `res = ajax().then(transform); onDecision(function(){ res.then(goOn) });` you could have used `ajx = ajax(); onDecision(function(){ ajx.then(function(r) { goOn(transform(r)) }) });` as well. – Bergi Oct 01 '13 at 21:35
  • @confile: It's not a "is it available?" question, it is more like a "when it is available, *then* do" statement. – Bergi Oct 01 '13 at 21:35
  • Ok, and the done in the ajax2 part is equivalent to complete? Or is there a reason for doing done instead of complete? – Michael Oct 01 '13 at 21:42
  • 1
    Nah, it's equivalent to `success` to be nitpicking. But there's no real reason to use one over the other here, I just think using the promise methods look cleaner :-) – Bergi Oct 01 '13 at 21:48
  • Ok and why do you use two then? I still don't get this point. – Michael Oct 01 '13 at 21:50
  • 1
    Again, it looks cleaner :-) With the first then separated from the rest, the JSON response will always be parsed, right when ajax1 resolves even when the user didn't click yet, and won't need to be parsed multiple times assuming there were multiple listeners waiting for it. – Bergi Oct 01 '13 at 21:53
  • I think you do not have to parse the response in the then function block. – Michael Oct 01 '13 at 22:27
  • Can I cancel the first ajax request somehow even if it has not been finished? – Michael Oct 01 '13 at 23:29
  • @confile: All [`jqXHR` objects](http://api.jquery.com/jQuery.ajax/#jqXHR) have an `.abort()` method. Promises in general don't, you'd need to notify the responsible Deferred to reject it. – Bergi Oct 02 '13 at 00:19
  • Can you please answer my question on this: http://stackoverflow.com/questions/19128083/jquery-access-xmlhttprequest – Michael Oct 02 '13 at 00:21