Wait for list of functions to complete then reload page

I have lots of different functions that send AJAX requests to save different parts of the page. When the user clicks save, All these functions are run like so.

function savePage() {
    if (!confirm('Save changes?')) return false;
    saveSortOrder();
    saveAllWidth();
    saveAllTinyMCE();
    saveAllWidgetRm();

    location.reload();  
}

Once everything is saved, I want to reload the page but location.reload() runs before everything is finished.

A typical save function looks like this but some are much bigger and there are lots of them

function saveAllPublic() {
    $('.widget').each( function(){

        var parentID = $(this).attr('id');
        var publicState = $(this).attr('data-public');

        $.post('widgets/manage_widgets.php', {
            update: 'publicity',
            wd_parent: parentID,
            public: publicState
        });

    });
}

Basically, I want all the POSTs to complete before reloading the page.

1 answer

  • answered 2017-08-12 09:47 Terry

    First of all, you will want the save functions to return an array of promises. We can do that by simply using .map(), and within in return the AJAX call you have made, i.e.:

    // saveAllPublic() will return an array of promises
    function saveAllPublic() {
        return $('.widget').map(function(){
    
            var parentID = $(this).attr('id');
            var publicState = $(this).attr('data-public');
    
            return $.post('widgets/manage_widgets.php', {
                update: 'publicity',
                wd_parent: parentID,
                public: publicState
            });
        }).get();
    }
    

    Note: Remember to use .get() at the end of .map(), in order to obtain a true array and not a jQuery collection (which is an array-like object). See a more thorough explanation here: map() get() confusion

    When you want to check if all the requests made by saveAllPublic() is done, you can simply do this:

    var saveAllPublicAJAX = saveAllPublic();
    $.when.apply($, saveAllPublicAjax).then(function() {
       // Callback when all POST requests in saveAllPublic() is completed
    });
    

    And let's say based on your example you have refactored all the save functions to use the array push method I have mentioned above, you can simply concatenate all these returned arrays into a single one, and pass it to $.when:

    function savePage() {
        if (!confirm('Save changes?')) return false;
    
        var saveAJAX = [].concat.apply([], [
            saveSortOrder(),
            saveAllWidth(),
            saveAllTinyMCE(),
            saveAllWidgetRm()
        ]);
    
        $.when.apply($, saveAJAX).then(function() {
            // When all the requests are successful
            location.reload();  
        }, function() {
            // When one or more requests have failed
            // ...
        });
    }
    

    There are, of course, other more verbose way of constructing the array, such as:

    • var saveAJAX = saveSortOrder().concat(saveAllWidth()).concat(...)
    • var saveAJAX = []; saveAJAX.push(saveSortOrder()); ...