The problem: I need a single callback after executing three functions of the form $(#myid).load()
But I can't get this to work without using setTimeout()
While my knowledge of jQuery promises / deferreds is, to be charitable, limited I believe the solution is in a simple use of jQuery's $.when().then()
functionality as advertised on
Javascript Callback and multiple ajax Request single callback jQuery
Here's my code:
$.when(
SetSelect('AJAXSetSelect.asp',valTable,'RECALBodySum'),
SetSelect('AJAXSetSelect.asp',valTable,'RECALCol1'),
SetSelect('AJAXSetSelect.asp',valTable,'RECALRow1')
)
.then(
function() { // success
setTimeout(function(){
$("#OutputAdvanced").load("/_RECAL/Modes/AdvancedCrosstab.asp",
{
"RECALtable":$('#RECALtable').children().val(),
"RECALCol1":$('#RECALCol1').children().val(),
"RECALRow1":$('#RECALRow1').children().val(),
"RECALBodySum":$('#RECALBodySum').children().val()
}
); // close load
}, 500) // why do we need 500 ms delay?
, // finished "success" fn, now "failure fn
function () {SF('failure'); // this is actually a simple alert
} // failure
); // close then
In summary the code makes three AJAX calls, each populating one SELECT box. When they're complete it populates the area #OutputAdvanced
, depending on the values of the three SELECTs.
I had thought that the whole point of the $.when().then()
construct is that code within the then()
is only run once the when()
is complete. I shouldn't have to introduce a delay with setTimeout
.
I've built a jsFiddle, but this is only a synchronous example and wasn't illuminating enough for me.
I'm also aware of frameworks such as asyncJS, but I believe that it's over the top for what I want to achieve. It didn't work in my specific example, and I really want to understand what I'm missing to build on my expertise - not just "solve the problem" - I did this using setTimeout
.
UPDATE 1 14 Jan - following research: The last jQuery example at api.jquery.com/jQuery.when/ is as follows:
$.when( $.ajax( "/page1.php" ), $.ajax( "/page2.php" ) )
.then( myFunc, myFailure );
My naive interpretation was that enclosing functions within the when()
ensured there was no need for deferred declarations. Previous example(s) on that page indicate that more is required:
var d1 = new $.Deferred();
var d2 = new $.Deferred();
$.when( d1, d2 ).done(function ( v1, v2 ) {
console.log( v1 ); // "Fish"
console.log( v2 ); // "Pizza"
});
d1.resolve("Fish");
d2.resolve("Pizza");
But what do d1 and d2 actually do? How would I use this with real world functions?
From jquery custom deferred functions at stackoverflow.com/questions/15018931/jquery-custom-deferred-functions I thought I should proceed as follows (with 3 new lines of code):
function PopulateTableSelect() {
return $.Deferred(function() { // AKHupdate2015/01/14
$('#RECALtable').load('/_RECAL/AJAX/AJAXSetSelect.asp',
{"RECALsubmode":'Aggregate',"RECALtable":'Risks',"RECALCol1Row1Id":'RECALtable'});
this.resolve(); // AKHupdate2015/01/14
}) // AKHupdate2015/01/14
}
The original example now runs three functions like PopulateTableSelect()
.
But I still seem to need the setTimeout()
with a 500 ms delay; without this the server doesn't get the SELECT values and the load()
then results in a server error.
UPDATE 2 14 Jan - following comment from @hindmost:
To avoid this becoming a "discussion" rather than a question I will remove this should I receive a complete answer
The suggestion in a comment is to avoid the problem by using ajax()
rather than load()
. This seems also to be the suggestion at looseideas.co.uk/using-ajax-rather-than-jquery-load (not enough rep to post full link). That looseideas approach proved too terse for me to interpret. But here are my old and new functions (minimal code omitted):
My old code using load()
was:
function SetSelect(AJAXfile, Table, IdToChange){
$('#' + IdToChange).load(
"/_RECAL/AJAX/" + AJAXfile, // URL
{ // data
"RECALsubmode":$('#RECALsubmode').children().val(),
// more data omitted
"RECALCol1Row1Id":IdToChange
}
); // close load
} // end SetSelect function
That worked, but only by using setTimeout()
My new code using ajax()
is:
function SetSelect(AJAXfile, Table, IdToChange){
$('#' + IdToChange).ajax({
type: "post",
url: "/_RECAL/AJAX/" + AJAXfile, // URL
data: {
"RECALsubmode":$('#RECALsubmode').children().val(),
// more data omitted
"RECALCol1Row1Id":IdToChange
},
dataType: "html" // attempt to prepare for data to be passed back
},function() {$('#' + IdToChange).html(responseText);} // callback is responseText right?
); // close .ajax
} // end SetSelect function
That didn't work; nothing is loaded into the id and I get a console message " Uncaught TypeError: undefined is not a function".
Finally I also looked at stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call but compared to my generic question and the simple code example at the end of the jQuery when()
documentation - see below - this seems very complex.
$.when( $.ajax( "/page1.php" ), $.ajax( "/page2.php" ) )
.then( myFunc, myFailure );