Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery .when troubleshooting with variable number of arguments

I'm having an issue with using jQuery.when() to wait for multiple ajax requests to finish before calling another function.

Each ajax request will get JSON data, and looks something like this:

   function loadData(arg){
        var ajaxCall = $.ajax(
            URL // depends on arg
        )
       .error( .... );
       return ajaxCall;
   }

When the request is called, the return value (ajaxCall) is added to a list called ajaxRequests.

    ajaxRequests = [];
    ajaxREquests.push(loadData(arg))

When all the requests have been made, I'm trying to pass ajaxRequests to $.when in order to wait for all requests to complete.

        var defer = $.when.apply($, ajaxRequests);
        defer.done(function(args){
            for (var i=0; i<args.length; i++){
                inst.loadData($.parseJSON(args[i].responseText));
            }
            inst.draw();
        });

inst is an object that loads and draws graphs based on JSON data.

The problem is that it doesn't seem to be actually waiting for the requests to finish - args[i] is an object, but responseText is undefined when the code runs. If I save args[i] and access it later from the console, it works.

I suspect the problem is related to using .when with an arbitrary number of arguments, as all the examples I've seen on the web give it a pre-defined argument list.

I'm not sure if using apply was the right idea or not, but either way it doesn't work properly and behaves erratically (browser-dependent).

Any help would be greatly appreciated.

Please let me know if more information is required.
I'm using jQuery 1.5

like image 502
Alex Avatar asked Mar 26 '12 01:03

Alex


4 Answers

Although Alex did indeed provide a solution to his problem, I found following it a bit difficult. I had an issue similar to his that I solved, and I wanted to share my solution for anyone else who needs to process a variable number of ajax requests.

// Array of requests
var requests = Array();
requests.push($.get('responsePage.php?data=foo'));
requests.push($.get('responsePage.php?data=bar'));

var defer = $.when.apply($, requests);
defer.done(function(){

    // This is executed only after every ajax request has been completed

    $.each(arguments, function(index, responseData){
        // "responseData" will contain an array of response information for each specific request
    });

});
like image 178
Andy Corman Avatar answered Nov 16 '22 08:11

Andy Corman


In addition to Andy Corman's answer (I am yet unable to reply to a post, I think ...), if you only have one request, the response information will be passed directly to the defer.done - function as an argument; So you need to provide an if for that case:

// Array of requests
var requests = Array();
requests.push($.get('responsePage.php?data=foo'));

var defer = $.when.apply($, requests);
defer.done(function(){

    // This is executed only after every ajax request has been completed
    if (requests.length == 1)
        // "arguments" will be the array of response information for the request
    else
        $.each(arguments, function(index, responseData){
            // "responseData" will contain an array of response information for each specific request
        });
});
like image 40
DHainzl Avatar answered Nov 16 '22 08:11

DHainzl


I think I've worked it out now - the problem was in processing the returned arguments. .done was getting passed three arguments only - the response text, status and jqXHR object. I was expecting it to get passed the jqXHR object resulting from each query.

I've solved it by moving the callback code for each query to a separate function (i.e. the ajax call in loadData is now specifying a callback function which does the '.loadData(...)' call) and the only thing being done by the .done call is the inst.draw(). This seems to work fine: the individual callback's are each execute before .done().

I'm not sure if that's exactly how it's supposed to work, but it seems to be doing the job.

like image 4
Alex Avatar answered Nov 16 '22 09:11

Alex


Try ajaxStart and ajaxStop, which have listeners for open ajax requests.

http://api.jquery.com/ajaxStart/ http://api.jquery.com/ajaxStop/

like image 1
user1289347 Avatar answered Nov 16 '22 09:11

user1289347