froadie
froadie

Reputation: 83033

How can I get my code to wait till all the code in a loop executes before continuing?

I'm iterating through a group of html elements using a jquery each. On each iteration I invoke a get. I want to keep track of the successful gets and output a count at the end.

var numSuccessful = 0;
$('.mySelector').each(function(){
    $.get('/myCfc.cfc?method=doSomething&id=' + $(this).attr('id'), 
        function(data){
            numSuccessful++;
    });
});
alert(numSuccessful + ' successful');

The problem with this code is that the each method starts off all the get calls and then continues to the alert before completing the gets - and before the numSuccessful variable is updated. On a test run, I ended up with "0 successful" instead of "4 successful" because the alert executed too quickly. How can I get the code to wait till all the gets complete before continuing? Is there a success callback for the entire "each" statement?

Upvotes: 4

Views: 286

Answers (4)

m90
m90

Reputation: 11812

You could use the promise returned by $.ajax to setup a flexible callback queue like this:

var requests = []; //Array containing all the ajax calls

for (var i = 0; i < 9; i++) {
    requests.push(
    $.ajax({
        url: '/echo/html', //this is because of jsfiddle.net
        type: 'post', //this one too
        success: function() {
           //whatever
        }
    }));
}

$.when.apply($, requests).then(function() { //.apply is needed as we want to pass an Array
  //called when all requests are done
}).fail(function(){ //this will be triggered when one of the requests fails
  //error handling can go here
});

See this working fiddle and read about .when() and .then

In your case that would end up in:

var numSuccessful = 0;

var requests = $.makeArray($('.mySelector').map(function(){
    return $.ajax({
        url: '/myCfc.cfc?method=doSomething&id=' + this.id,
        type: 'GET'
    }).done(function(){
        numSuccessful++;
    });
}));

$.when.apply($, requests).then(function() {
    alert(numSuccessful + ' successful');
});​

Upvotes: 1

Abhishek
Abhishek

Reputation: 836

Just replace $.get with $.ajax and set async setting to false.

$.ajax({
    url : '/myCfc.cfc',
    data : { 'method' : 'doSomething' , 'id' : $(this).attr('id') },
    async : false,
    success : function(data){
       numSuccessful++;
    }
});

By doing this script will wait until it will get response.

Upvotes: 1

Ram
Ram

Reputation: 144659

You can use a recursive function, try the following:

var num = 0;
var $ms = $('.mySelector');

function go() {
     $.get('/myCfc.cfc?method=doSomething&id='+$ms.eq(num).attr('id'), 
       function(data){
            num++;
            if ((num-1) == $ms.length) callback(); else go();
     }).error(callback)
}

function callback(){
  alert(num)
}

go()

Upvotes: 1

Ariel
Ariel

Reputation: 26753

var numSuccessful = 0;
var totalSelectors = $('#mySelector').length;
$('#mySelector').each(function(){
  $.get('/myCfc.cfc?method=doSomething&id=' + $(this).attr('id'), 
  function(data){
    numSuccessful++;
    if(!totalSelectors--) doneSelectors();
  });
});

function doneSelectors() {
  alert(numSuccessful + ' successful');
}

Note: The above function does NOT work properly! The $.get() does not notify on errors, so if you get any errors the final function will never run.

Instead you need to convert it to use the $.ajax() function. And define both success and failure callbacks. If you need help doing that let me know.

Upvotes: 0

Related Questions