0
votes

I have to make a call to the Agile Central API to get a list of defect suites and then iterate through the list and make a nested call to get the list of defects in each suite, the nested call depends on the outer call. I then have to append the rows of data to a table and then call doneCallback() to signal the end of data collection. The problem I'm having is that doneCallback() is being called before the requests have completed so none of the data is actually passed on

I've tried the approaches in this post: Wait until all jQuery Ajax requests are done? and this post: how to wait until Array is filled (asynchronous). In the console I can see that all the data I want is there but nothing gets appended. My question is: how can I make sure I don't call doneCallback() until all the requests that are made in the loop have finished and pushed the data? Here's my code right now:

function getSuites() {
        return $.ajax({
            url: suitesURL("71101309592") + "&fetch=Name,FormattedID,Defects",
            type: "GET",
            xhrFields: {
                withCredentials: true
            },
            headers: {
                "zsessionid": apiKey
            }
        });
    }

    function getDefects(_ref) {
        return $.ajax({
            url: _ref,
            type:"GET",
            xhrFields: {
                withCredentials: true
            },
            headers: {
                "zsessionid": apiKey
            }
        });
    }

    // Download the data
    myConnector.getData = function (table, doneCallback) {

        console.log("Getting Data...");

        var ajaxCalls = [], tableData = [];

        var suitesJSON = getSuites();

        suitesJSON.done(function(data) {

            var suites = data.QueryResult.Results;

            for(var i = 0; i < suites.length; i++) {

               (function(i) {
                    var defectsJSON = getDefects(suites[i].Defects._ref + "?fetch=Name,FormattedID,State,Priority,CreationDate,c_RootCause,c_RootCauseCRM");
                    ajaxCalls.push(defectsJSON);

                    defectsJSON.done(function(data) {
                        var defects = data.QueryResult.Results;

                        for(var j = 0; j < defects.length; j++) {
                            tableData.push({
                                "suiteName": suites[i].Name, // This is the name of the suite collected in the outer call
                                "defectName": defects[j].Name,
                                "FormattedID": defects[j].FormattedID,
                                "State": defects[j].State,
                                "Priority": defects[j].Priority,
                                "CreationDate": defects[j].CreationDate,
                                "RootCause": defects[j].c_RootCause,
                                "RootCauseCRM": defects[j].c_RootCauseCRM
                            });
                        }

                    });
               })(i);

            }

        });


        $.when.apply($, ajaxCalls).then(function() {
            console.log(tableData);
            table.appendRows(tableData);
            doneCallback();
        });
};
2
jQuery when() with the ajax calls should be fine....epascarello
Sorry, I'm pretty new to using ajax... could you explain a little more please?James Prescott

2 Answers

1
votes

You should use a better model to get multiple items. Using a for loop to query for multiple gets is the problem, and the solution should be to refactor so that you make one request that returns everything you need.

If this doesn't seem possible to you, I've researched a way to do what you want in jQuery.

$.when(
    $.get(path, callback), $.get(path, callback), $.get(path, callback)
.then({
    //This is called after all requests are done
});

You could create an array of all your requests like [$.get(path, callback), request2, request 3, etc...] and then use the spread method to put them as arguments like

var args = [$.get(path, callback), request2, request 3, etc...];
$.when(...args).then(() => {/*call here*/});

This link has the rest of the information https://css-tricks.com/multiple-simultaneous-ajax-requests-one-callback-jquery/

0
votes

I think the problem is that you are calling $.wait right after getSuites() is executed.

$.wait 'sees' the ajaxCalls array empty (because getSuites() hasn't finish yet) and executes doneCallback().

Try to call $.wait INSIDE the suitesJSON.done function, that way it will be called after the ajaxCalls array is filled with the first response:

myConnector.getData = function (table, doneCallback) {
    console.log("Getting Data...");
    var ajaxCalls = [], tableData = [];

    var suitesJSON = getSuites();

    suitesJSON.done(function(data) {

        var suites = data.QueryResult.Results;

        for(var i = 0; i < suites.length; i++) {

           (function(i) {
                var defectsJSON = getDefects(suites[i].Defects._ref + "?fetch=Name,FormattedID,State,Priority,CreationDate,c_RootCause,c_RootCauseCRM");
                ajaxCalls.push(defectsJSON);

                defectsJSON.done(function(data) {
                    var defects = data.QueryResult.Results;

                    for(var j = 0; j < defects.length; j++) {
                        tableData.push({
                            "suiteName": suites[i].Name, // This is the name of the suite collected in the outer call
                            "defectName": defects[j].Name,
                            "FormattedID": defects[j].FormattedID,
                            "State": defects[j].State,
                            "Priority": defects[j].Priority,
                            "CreationDate": defects[j].CreationDate,
                            "RootCause": defects[j].c_RootCause,
                            "RootCauseCRM": defects[j].c_RootCauseCRM
                        });
                    }

                });
           })(i);

        }

        $.when.apply($, ajaxCalls).then(function() {
            console.log(tableData);
            table.appendRows(tableData);
            doneCallback();
        });
    });
};