1

Edit - please see notes at the bottom on why I don't believe this is a duplicate question

Using jquery 3.2.1 and Bootstrap 3.3.7

Part of my application has the following flow:

  1. A user clicks on an anchor inside a modal window with an ID of #notifierModal

  2. This makes the first ajax request which writes to a database storing preferences on choices a user makes (each choice is an anchor from step 1 - clicking toggles the preference on/off). The response from this ajax request is JSON which is in the following format:

    {result: "success", message: "Notification preference has been updated"}

If there was an error - in terms of making a database update - the JSON is of a similar structure but would have {result: "error"} and an appropriate message.

  1. A second ajax request is made to update the contents of the modal (#notifierModal). This is effectively to "refresh" the data shown in the modal following updating preferences in a database from step 2.

  2. The result (success or error message) given by the response from step 2 is updated inside #notifierModal.

My question - I have implemented the above with the following ajax:

// Step 1
$('#notifierModal .modal-body').on('click', '.toggle-notifier a', function(e) {
    e.preventDefault();

    // Step 2
    $.ajax({
        url: $(this).attr('href'),
        method: 'get'
    }).then(function(response2) {

        // Step 3
        $.ajax({
            url: '/notifier-modal',
            method: 'get'
        }).then(function(response3) {

            $('#notifierModal .modal-body').html(response3);
        }).done(function() {

            // Step 4
            if (response2.result == 'error') {
                $('#notifierModal .modal-body .outcome').html(response2.message); 
            }
            if (response2.result == 'success') {
                $('#notifierModal .modal-body .outcome').html(response2.message); 
            }
        });       
    }); 
});

However, if I replace both instances of .then() with .done() it works in exactly the same way.

I am trying to ensure that the first ajax request (step 2) completes before continuing to making the second ajax request (step 3). I have read about Promises and the information on How do I chain three asynchronous calls using jQuery promises?

I don't understand why using .done() gives the same outcome and which is the correct approach? I appreciate there may be other improvements I can make to the js but my question here is concerning the difference between using .done() on it's own versus a .then()/.done() approach?

My application is "working" - in the sense it gives the same results from both ways - but I feel like I'm making a mistake because I don't understand the difference between these approaches. Please can someone clarify this?

Not a duplicate: Someone suggested this is a duplicate of jQuery deferreds and promises - .then() vs .done(). I don't think it is because it says:

There is also difference in way that return results are processed (its called chaining, done doesn't chain while then produces call chains)

I've updated the variables in callbacks to response2 and response3 to show which step they are in within the js. However, I can use response2 (from step 2) inside step 4 irrespective of whether I use .done() or .then(). How is that possible? The outcome is what I want, but I don't understand how it's working, which is concerning.

Andy
  • 5,142
  • 11
  • 58
  • 131
  • Take a look at the `Promose.all()` API ? – Arup Rakshit Aug 20 '18 at 11:22
  • I've read the documentation but don't understand it in context of my question. If you can explain it in context of my question that would be very helpful. – Andy Aug 20 '18 at 11:25
  • For then vs done this may be useful: https://stackoverflow.com/questions/5436327/jquery-deferreds-and-promises-then-vs-done – Bram Vanroy Aug 20 '18 at 11:44
  • Possible duplicate of [jQuery deferreds and promises - .then() vs .done()](https://stackoverflow.com/questions/5436327/jquery-deferreds-and-promises-then-vs-done) – Domenik Reitzner Aug 20 '18 at 11:45
  • Maybe you are using response parameter name for two request. Try to change response parameter name on the second ajax. – Kadir Çetintaş Aug 20 '18 at 11:54
  • Never use the `done` method. In your script, just drop the line `}).done(function() {` and put the `$('#notifierModal .modal-body').html(…)` in the same `then` callback function as the "step 4" code. – Bergi Aug 20 '18 at 12:53
  • "*how am I able to use response in the callback from Step 2 inside Step 3*" - see [How do I access previous promise results in a `.then()` chain?](https://stackoverflow.com/q/28250680/1048572) – Bergi Aug 20 '18 at 12:53
  • @Bergi when I said "how am I able to use" what I mean is that I **am** able to use it, but don't understand why! I've updated the code and used the variables `response2` and `response3` to show which step they appear. I can use `response2` inside the callback during Step 4, irrespective of whether I use `.done()` or `.then()`. I don't understand how/why that's possible given the information and links people have shared? – Andy Aug 20 '18 at 13:08
  • @Andy Because you have written the step 4 callback as a closure *inside* the step 2 callback - the `response2` parameter simply is in scope. This has nothing to do with using `then` or `done`. – Bergi Aug 20 '18 at 13:17
  • Ok, I understand now about the scope. But given that I'm making 2 separate ajax requests (step 2 and 3), does it not matter whether I use `done()` or `then()` in terms of them executing in this order? I need step 2's ajax request to complete before step 3's. If my code does this correctly then I don't need any further information. – Andy Aug 20 '18 at 13:24

2 Answers2

2

This question is duplicate. jquery-deferreds-and-promises-then-vs-done

In short:

promise.then( doneCallback, failCallback )
// was equivalent to
promise.done( doneCallback ).fail( failCallback )
morteza ataiy
  • 541
  • 4
  • 12
0

If I had correctly understood what you're trying to do, it seems that you need to update the modal content with the step 2 response, but only after loading the content in step 3. if that is the Problem, then :

$('#notifierModal .modal-body').on('click', '.toggle-notifier a', function(e) {
    e.preventDefault();

    // Step 2
    $.ajax({
        url: $(this).attr('href'),
        method: 'get'
    }).then(function(outcome) {

        // Step 3
        $.ajax({
            url: '/notifier-modal',
            method: 'get'
        }).then(function(response) {
            $('#notifierModal .modal-body').html(response);
            // Step 4
            if (outcome.result == 'error') {
                $('#notifierModal .modal-body .outcome').html(outcome.message); 
            }
            if (outcome.result == 'success') {
                $('#notifierModal .modal-body .outcome').html(outcome.message); 
            }
        });       
    }); 
});