Reputation: 141
I have this inside an ajax function
$.each(data['Result'][0], function(Key, Value) {
InputGen(Value['Type'], Value['Name'], Value['Other'], Value['Value'], function(Html){
Table = Table + "<tr><td>"+Key+"</td><td>" + Html + "</td></tr>";
});
});
and InputGen
has a callback from another ajax function but when i run this the loop does not seem to be waiting for the ajax to finish. how would i achieve this?
Upvotes: 1
Views: 3811
Reputation: 1074058
...the loop does not seem to be waiting for the ajax to finish.
No, because the "a" in "ajax" stands for asynchronous; it doesn't happen when you make the call, it happens later. But there's no reason the $.each
loop would know to sit around and wait for it to finish.
If you don't need it to (e.g., it's okay for the ajax calls to overlap, which normally it should be unless they rely on each other), look at Rocket Hazmat's approach.
If you need each ajax call to wait for the previous one to finish, you can't use $.each
(or at least, not the way you were); instead, use an index and respond to the callback by triggering the next request:
// Start with first entry
var index = 0;
var array = data['Result'][0];
// Do the first request
doRequest();
function doRequest() {
var value = array[index];
InputGen(value['Type'], value['Name'], value['Other'], value['Value'], function(Html) {
Table = Table + "<tr><td>"+index+"</td><td>" + Html + "</td></tr>";
// This request is done, move to the next if any
if (++index < array.length) {
doRequest();
}
});
}
Side note: Overwhelmingly in JavaScript, variables and non-constructor functions are named starting with a lower-case letter: value
rather than Value
, etc. So I used index
, array
, and value
above.
Side note 2: value['Type]
can be more simply written as value.Type
. (And so on.)
Upvotes: 3
Reputation: 227200
This is because AJAX is asynchronous. Nothing is going to wait for it to finish. The callback will run in the future at some point when the call is done. By then your $.each
(and the code after) is long done.
The solution here is to use promises. That way you can run a callback once all the AJAX calls are done.
You can use jQuery's $.Deferred
for this. Without editing the InputGen()
function, you can do something like this:
var promises = [];
$.each(data['Result'][0], function(Key, Value) {
var d = new $.Deferred;
InputGen(Value['Type'], Value['Name'], Value['Other'], Value['Value'], function(Html){
d.resolve([Key, Html]);
});
promises.push(d.promise());
});
$.when.apply($, promises).done(function(){
for(var i=0, length=arguments.length; i < length; i++){
var ele = arguments[i],
Key = ele[0],
Html = ele[1];
Table = Table + "<tr><td>"+Key+"</td><td>" + Html + "</td></tr>";
}
// In here is where you can use your updated `Table` variable.
// You *cannot* use it outside of here, since it was not updated yet
});
Upvotes: 2