0

I'm sure I've seen this before and know the answer to it but after 12 hours... my mind is complete mush.

I have a for loop in which I am trying to concatenate onto a string so that AFTER I can complete the string (thus completing a nice little table) that I had hoped to then insert into my html and show the user.

However, the things at the end of my function (after my for loop) are getting called before the for loop ever does....

function getEntries() {

$('#entryTotalsDiv').html('<img src="images/ajax-loader.gif" /> ... retrieving form totals.');

var entryTotalsTable = "<table id='entryTable' class='display' style='border:1px;'><thead><tr><th>Form Name</th><th>Hash</th><th>Entries</th></tr></thead>" +
        "<tbody>"

//Get rows ONE at a time.
var countNumber = 1;
for (var frm = 0; frm < numberOfForms; frm++) {
    $.post('ajax/getEntries.aspx',
    {
        'formNumber': frm
    },
    function (data) {
        entryTotalsTable += "<tr><td>" + data[0].formName + "</td><td>" + data[0].formHash + "</td><td>" + data[0].formEntryCount + "</td></tr>";

        //Now go and update the Form Retrieval div -- add 1 to the frm Number
        $('#formNamesDiv').html(countNumber + ' of ' + numberOfForms + ' retrieved.');
        countNumber++;            
    });
}
entryTotalsTable += "</tbody></table>";
$('#entriesDiv').html(entryTotalsTable);
//Now bind the table to the DataTables JQ script
$('#entryTable').dataTable();
$('#entryTable').show('slow');

}

If you notice, I wanted to close up the Table html at the end, but this gets called before my for loop is finished, thus screwing up my string...

?

entryTotalsTable += "</tbody></table>";
$('#entriesDiv').html(entryTotalsTable);
//Now bind the table to the DataTables JQ script
$('#entryTable').dataTable();
$('#entryTable').show('slow');

}

Todd Vance
  • 4,627
  • 7
  • 46
  • 66

2 Answers2

2

A solution could be to save every response in an array and test in every callback whether the current count is equal to the total count. Something like:

var countNumber = 1,
    allData = [];

function runWhenFinished() {
    if(countNumber === numberOfForms) {
        var entryTotalsTable = "<table id='entryTable' class='display' style='border:1px;'><thead><tr><th>Form Name</th><th>Hash</th><th>Entries</th></tr></thead>" + "<tbody>";

        for(var i = 0, l = allData.length; i < l; i++) {
             entryTotalsTable += "<tr><td>" + allData[i].formName + "</td><td>" + allData[i].formHash + "</td><td>" + allData[i].formEntryCount + "</td></tr>";
        }

        entryTotalsTable += "</tbody></table>";
        $('#entriesDiv').html(entryTotalsTable);
        //Now bind the table to the DataTables JQ script
        $('#entryTable').dataTable();
        $('#entryTable').show('slow');
    }
}

for(var frm = 0; frm < numberOfForms; frm++) {
    (function(frm) {
        $.post('ajax/getEntries.aspx',{'formNumber': frm}, function (data) {
            allData[frm] = data[0];
            countNumber++;
            $('#formNamesDiv').html(countNumber + ' of ' + numberOfForms + ' retrieved.');
            runWhenFinished();
        });
    }(frm));
}

I'm sure this can still be improved, but you get the idea.


If you really make 70 requests then you might want to rethink your strategy anyway. 70 simultaneous requests is a lot.

E.g. you could make one request and prove the minimum and maximum number of that should be retrieved / updated / whatever the method is doing.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • +1 - Doesn't really answer the question, but does provide a better option. – Pete - MSFT Jun 01 '11 at 04:31
  • thanks for the suggestion -- I am doing the count thing and then just calling the next function when the count reaches my limit. THE REASON I am doing one call at a time instead of one large call (like I was doing) is that I was trying to give the user some feedback (so with each return, I am updating the count of returns to the users -- the ONE call just took quite a while) **I also thought it would be SUPER COOL to fill in my table dynamically on the fly, this was working but all the good jquery gridview stuff was not getting applied (i.e. paging, etc) so I went away from that. – Todd Vance Jun 02 '11 at 11:57
1

$.post is asynchronous, meaning that it's firing off all the requests in the loop as fast as it can, and then exiting the loop. It doesn't wait for a response. When the response comes back, your row function is then called... but by then, all the posts have been sent on their way.

See the answers to this question here... How can I get jQuery to perform a synchronous, rather than asynchronous, Ajax request?

You'll need to change from $.post to $.ajax

Community
  • 1
  • 1
Pete - MSFT
  • 4,249
  • 1
  • 21
  • 38
  • 2
    Making several *synchronous* Ajax calls might result in freezing the browser (or at least the page)! Everything that takes longer than 100ms will be noticed by the user. – Felix Kling Jun 01 '11 at 01:33
  • Very true - hopefully numberOfForms isn't more than 2! – Pete - MSFT Jun 01 '11 at 04:29