XF 2.0 .each() loop runs concurrently, instead of in order...

Jaxel

Well-known member
I have a table with 8 rows. I execute some jQuery on this table:

Code:
init: function()
{
    $target = this.$target;
    
    var process = true,
        eventID = $target.data('event'),
        href = $target.data('href');
    
    $target.find('.formRow').each(function()
    {
        var $row = $(this);
        var $fa = $row.find('dt i');
        
        if (process)
        {
            var input = {
                'eventID': eventID,
                'userID': $row.data('user'),
                'seed': $row.data('seed'),
            };
            
            XF.ajax('POST', href, input, function(data)
            {
                $fa.removeClass().addClass('fa fa-check-circle-o');
            },
            function(data)
            {
                process = false;
                $fa.removeClass().addClass('fa fa-exclamation-triangle');
            });
        }
        else
        {
            $fa.removeClass().addClass('fa fa-exclamation-triangle');
        }
    });
},

This code looks at each row of the table and runs an AJAX post on that row. Each loop MUST run in order, after the previous iteration completes.

The problem I am having is it runs all 8 AJAX posts at the same time... instead of one after another. How do I fix this?

Also, how do I get the XF.ajax call to do something on failure?
 
Last edited:
The loop technically runs in order, but XF.ajax returns immediately (it doesn't wait for the request to complete). I think you can pass async: false as an option to prevent this.
 
The loop technically runs in order, but XF.ajax returns immediately (it doesn't wait for the request to complete). I think you can pass async: false as an option to prevent this.
async: false is deprecated... as well, the fa class additions don't process till the end.
 
The class changes are inside the callback, and the callback isn't executed until the request completes. Everything outside of it (including the loop) will continue without waiting for the request to complete.

It looks like in lieu of the deprecated async option, they recommend using the callbacks. So I think you'd have to restructure your code such that you trigger the next request inside the callback of the previous one, basically using recursion instead of $.each().

I'd start by grabbing all the rows (var $rows = $target.find('.formRow');) and creating a function that takes the rows object and an index as arguments. Inside that function, you can then grab a single row var $row = $rows[index], perform the ajax request for this row, and have the callback call the function again with the next index (if it exists, or simply return if it doesn't).
 
I'm suggesting using recursion (a function that calls itself) instead of $.each() to allow performing the request for the next row inside the request completion callback of the current row. Here is a (untested) minimal example:

JavaScript:
init: function()
{
    // ...

    var $rows = this.$target.find('.formRow');
    this.doThing($rows);
},

doThing: function($rows, index)
{
    index = (typeof index === 'undefined') ? 0 : index;

    if (typeof $rows[index] === 'undefined') {
        return;
    }

    var $row = $rows[index];

    // ...

    var self = this;
    XF.ajax('POST', href, input, function(data)
    {
        // ...

        self.doThing($rows, (index + 1));
    }
}
 
Thats what someone on stackoverflow recommended... with done/fail promises. and it did the trick.
 
Top Bottom