0

Using jQuery promises, I'm trying to:

  1. Call an API for all possible values (of an animal)
  2. Call an API method for each animal (animal sound)
  3. Notify when each animal sound comes back - let's say it takes a while to work out
  4. Notify when all animal sounds have been returned

I'm putting all the animal sound functions into an array then calling $.when(). I expect this to resolve when all animal sounds have returned, but I'm finding that it resolves immediately. Does anyone know what I'm doing wrong?

function () {
  $('#txtNotification').text('Started ....');

  $.ajax({
    url: "/api/animals/all"
  }).done(function(data) {
    var animalFunctions = [];

    for (var animalType of data) {
      var animalFunction = $.ajax({
        url: "/api/animal/sound/" + animalType
      }).done(function(data) {
        $('#txtNotification').text(data);
      });

      animalFunctions.push(animalFunction);
    }

    $.when(animalFunctions).then(function() {
      $('#txtNotification').text('Done.');
    });
  });
}
MTCoster
  • 5,868
  • 3
  • 28
  • 49
Crab Bucket
  • 6,219
  • 8
  • 38
  • 73
  • 1
    [`$.when()`](https://api.jquery.com/jquery.when/) is one of the few jQuery functions which [cannot accept an array](https://stackoverflow.com/q/5627284/1813169) – MTCoster Feb 08 '19 at 02:37
  • 1
    Adding on to @MTCoster's comment, try changing `$.when(animalFunctions)` to `$.when(...animalFunctions)`. The spread operator (`...`) can turn your array into a list of arguments. – Tyler Roper Feb 08 '19 at 02:38
  • 1
    That’s what I’d recommend. The pre-ES6 solution would have been `$.when.apply($, animalFunctions)` – MTCoster Feb 08 '19 at 02:39
  • @MTCoster. Brilliant. That's worked. I would have never have got that. If you write it as an answer I will upvote and accept. Thanks for the help – Crab Bucket Feb 08 '19 at 02:48

3 Answers3

1

$.when() is one of the few jQuery functions which cannot accept an array - you’ll need to call it with each promise as a separate argument:

The ES6 way:

$.when(...animalFunctions).then(() => {
  $('#txtNotification').text('Done.');
});

The stone age way:

$.when.apply($, animalFunctions).then(function () {
  $('#txtNotification').text('Done.');
});
MTCoster
  • 5,868
  • 3
  • 28
  • 49
0

jQuery's Deferred.promise() allows you to "notify" the progress of the individual items.

var $def = jQuery.Deferred();

$.ajax({
  url: "https://jsonplaceholder.typicode.com/users"
})
.done(function getUsersAsync(users) {
  for (var user of users) {
    $def.notify(`Fetching comments of ${user.username}, ID: ${user.id}`);
    
    $.ajax({
      url: "https://jsonplaceholder.typicode.com/comments",
      data: JSON.stringify({ id: user.id })
    })
    .done(function (arg) {
      // Do stuff with the comments here
    });
  }
  
  $def.resolve(users.length);
})
.fail(function () {
  $def.reject('ERR: Failed retrieving comments');
});


$def
  .progress(function (message) {
    console.log(message);
  })
  .done(function (count) {
    console.log('ALL DONE. Total user: ' + count);
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Yom T.
  • 8,760
  • 2
  • 32
  • 49
-3

Add return: false to the anon function passed to .done(). See if that helps.

function () {
        $('#txtNotification').text('Started ....');

        $.ajax({
                url: "/api/animals/all"
            })  
            .done(function( data ) {

                var animalFunctions = [];

                for (var animalType of data) {

                    var animalFunction = $.ajax({
                            url: "/api/animal/sound/" + animalType
                        })
                        .done(function(data) {
                            $('#txtNotification').text(data);
                            return false;
                        }
                    );

                    animalFunctions.push(animalFunction);
                }

                $.when(animalFunctions).then(function() {
                    $('#txtNotification').text('Done.');
                });
            });
    }
Jay
  • 353
  • 4
  • 8