0

(My solution below)

I have several HTML elements with class .canvas-background of which information is stored in the database. I want to get the information of each element and process it via JavaScript. But somehow I can't pass the response of the AJAX request to another function. Here is what I've tried:

function initTabs() {
    var tabs = loadTabInformation();
    console.log(tabs); // (1)
    // do something else
}

function loadTabInformation() {
    var requests = new Array();
    var tabs = new Object();
    var counter = 0;
    $(".canvas-background").each(function () {
        var tabNumber = $(this).data("tab-number");
        var request = $.ajax({
            type: 'POST',
            url: '../db/GetTabInformation.ashx',
            data: String(tabNumber),
            dataType: 'json',
            contentType: 'text/plain; charset-utf-8'
        })
        .done(function (response) {
            tabs[counter++] = response;
        }).fail(function (jqXHR, textStatus, errorThrown) {
            console.log("request error in loadTabInformation()");
            console.log(textStatus);
            console.log(errorThrown);
        });
        requests.push(request);
    });
    $.when.apply($, requests).done(function () {
        console.log(tabs); // (2)
        return tabs;
    });
}

At (1) I get undefined, but at (2) everything seems to be alright.

THE SOLUTION:

Thanks to the answer and the link in the comment @Kim Hoang provided I got this working. The clue seemed to put the done() function in the calling function, that is initTabs() in my case. Another thing I got wrong was to try to do the logic that should be executed after the AJAX requests had finished outside the done callback function. They must be inside (makes sense, if you think about it). And a lot of conosle output helped, to see what function returns what kind of object.

function initTabs() {
    var tabInfoRequest = loadTabInfo();
    tabInfoRequest[0].done(function() {
        var results = (tabInfoRequest[1].length > 1) ? $.map(arguments, function(a) { return a[0]; }) : [arguments[0]];
        for (var i = 0; i < results.length; i++) {
            // do something with results[i]
        }
    });
}

function loadTabInfo() {
    var tabNumbers = new Array();
    $(".canvas-background").each(function () {
        tabNumbers.push($(this).data("tab-number"));
    });
    var requests = $.map(tabNumbers, function (current) {
        return $.ajax({
            type: 'POST',
            url: '../db/GetTabInformation.ashx',
            data: String(current),
            dataType: 'json',
            contentType: 'text/plain; charset-utf-8'
        });
    });
    var resultObject = new Object();
    resultObject[0] = $.when.apply($, requests);
    resultObject[1] = requests;
    return resultObject;
}

Note: I only did the resultObject-thing because I needed the array requests in the initTabs() function.

Thank you very much for helping me!

elementzero23
  • 1,389
  • 2
  • 16
  • 38

1 Answers1

4

You do not return anything in loadTabInformation, so of course you will get undefined. You should do it like this:

function loadTabInformation() {
    ...
    return $.when.apply($, requests);
}

function initTabs() {
    loadTabInformation().done(function (tabs) {
        console.log(tabs); // (1)
        // do something else
    });    
}
Kim Hoang
  • 1,338
  • 9
  • 24
  • OK, this puts me closer to the solution. But the `tabs` parameter of the function inside `done` only contains the first response. I tried adding `tabs2` and `tabs3` as parameters, and I got all three responses. Is it possible to do this for a variable number of responses? – elementzero23 Jan 05 '17 at 08:30
  • 1
    @elementzero23, you may want to look at this thread http://stackoverflow.com/questions/22416073/when-and-done-using-an-array-with-done for the way to handle array of promise in $.when. Basically you need to use the arguments object, each argument will contain [data, statusText, jqXHR] – Kim Hoang Jan 05 '17 at 08:39