Timo002
Timo002

Reputation: 3208

Do ajax calls in an each loop

I have a webpage and I'm having 5 checkboxes on this page. With a whileloop I'm running through all the selected checkboxes and will perform a AJAX call when checked.

The problem is that the order of the checkboxes is important. Or at least the first AJAX call must do something special before the other AJAX call can be done. However it seems that all the AJAX call are done in the right order, the PHP code behind is not executed in the same order which causes that the fist AJAX call is for example executed as third.

How will I be able to get this right? Below my code.

$("#submitforms").click(function(){
    var btn = $(this);
    var first = "true";
    var formsSend = 0;
    var formsToSend = $(":checkbox:checked").length
    var ids = "";
    console.log("To send: "+formsToSend);
    $('span.postable').each(function(index){
      console.log(index);
      add = $(this).find('[name="cc"]').is(':checked');
      if(add){
        btn.css("background-image", "url(/images/wait.gif)");
        btn.html("You will be redirected in a second!");
        sku = $(this).find('.sku').val();
        price = $(this).find('.price').val();
        XID = $(this).find('[name="XID"]').val(); 
        $.ajax({                            
          type: "POST",
          url: "/addtocart",   
          data: {sku:sku, qty:"1", price:price, XID:XID, first:first}   
        }).done(function(data) {
          formsSend++;
          console.log("Forms send: "+formsSend + " > "+index);
          if(formsSend >= formsToSend){
            // redirect to cart here after all forms have been posted
            console.log("forward");
            window.location.href = '/cart';

          }
        });
        first = "false";
      }
    });

In the console the following is shown.

To send: 5
0 
1 
2 
3 
4 
Forms send: 1 > 4 
Forms send: 2 > 0 
Forms send: 3 > 2 
Forms send: 4 > 1 
Forms send: 5 > 3 
forward 

As you can see, it sends form 1 with index 0, so the first Then it sends form 2, with index 4, then form 3 with index 2, etc.

So the order of where the forms are "done" is different from how they should be > 4,0,2,1,3 instead of 0,1,2,3,4. The order is each time different.

With the parameter first I wanted tel the script /addtocart that it's the first one in line so it should do something special. But unfortunately the first on is not always the first one.

BTW:

The order is not so important, the only thing that is important is that in the script /addtocart I must know that it's the first one.

Upvotes: 1

Views: 177

Answers (2)

iCollect.it Ltd
iCollect.it Ltd

Reputation: 93561

If you restructure your loop so that is simply collects the data needed for the Ajax calls in an array, you can use a recursive function to process the Ajax calls in sequence. This has the benefit that it happens async so does not block any other processing.

This is a quick hack together of this concept and your code...

$("#submitforms").click(function () {
    var btn = $(this);
    var first = "true";
    var formsSend = 0;
    var formsToSend = $(":checkbox:checked").length
    var ids = "";
    console.log("To send: " + formsToSend);
    var queue = [];
    $('span.postable').each(function (index) {
        console.log(index);
        add = $(this).find('[name="cc"]').is(':checked');
        if (add) {
            btn.css("background-image", "url(/images/wait.gif)");
            btn.html("You will be redirected in a second!");
            sku = $(this).find('.sku').val();
            price = $(this).find('.price').val();
            XID = $(this).find('[name="XID"]').val();
            queue.push({
                sku: sku,
                qty: "1",
                price: price,
                XID: XID,
                first: first
            });
        }
    });
    // Now process the queue of data and do processing once all request are completed
    ProcessQueue(queue, function () {
        formsSend++;
        console.log("Forms send: " + formsSend + " > " + index);
        if (formsSend >= formsToSend) {
            // redirect to cart here after all forms have been posted
            console.log("forward");
            window.location.href = '/cart';
        });
    });
});

// Recusively process the Ajax calls (actually this is just chained Async)
function ProcessQueue(queue, callback) {
    if (queue.length) {
        $.ajax({
            type: "POST",
            url: "/addtocart",
            data: queue[0]
        }).done(function (data) {
            ProcessQueue(queue.slice(1), callback);
        });
    } else {
        callback();
    }
}

Apologies for not taking into account your counters etc, but this should point you in the right direction (and is a generally useful technique).

While using promises is a great option, it becomes a bottleneck (especially on mobile) if you try to run loads of parallel ajax loads. I often fallback to sequential Async using this technique.

Upvotes: 1

Anto Subash
Anto Subash

Reputation: 3215

every ajax function will return a promise object make use of that. promises will contain all the ajax promises and $.when will resolve all the ajax calls and fire the callback done;

try this

$("#submitforms").click(function(){
    var btn = $(this);
    var first = "true";
    var formsSend = 0;
    var formsToSend = $(":checkbox:checked").length
    var ids = "";
    var promises = new Array(); // creating the array for promise.
    console.log("To send: "+formsToSend);
    $('span.postable').each(function(index){
      console.log(index);
      add = $(this).find('[name="cc"]').is(':checked');
      if(add){
        btn.css("background-image", "url(/images/wait.gif)");
        btn.html("You will be redirected in a second!");
        sku = $(this).find('.sku').val();
        price = $(this).find('.price').val();
        XID = $(this).find('[name="XID"]').val(); 
        var promise = $.ajax({                            
          type: "POST",
          url: "/addtocart",   
          data: {sku:sku, qty:"1", price:price, XID:XID, first:first}   
        })
       promises.push(promise);// pushing the promise to the array
      }
    });

    $.when.apply($, promises).done(function(){
          window.location.href = '/cart';
    });

});

Upvotes: 2

Related Questions