1

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 );
Community
  • 1
  • 1
coolactuary
  • 53
  • 1
  • 9
  • 2
    Your `SetSelect` function should return `Deferred` in order to `when` works properly. Is it so in your script? – hindmost Jan 13 '15 at 15:26
  • @hindmost It does not. I'm going away to see what exactly the syntax is to do this (declaration before function call, return value at end of function etc). I think I implied I had a lot to learn :) – coolactuary Jan 13 '15 at 16:54
  • @Ben and Khurram Thanks for your edits (particularly as I'm learning the SO submission ropes). I can see that they make my question less verbose. The edits also helped me learn SO conventions and functionality e.g. backtick escapes. – coolactuary Jan 14 '15 at 09:48
  • @hindmost Having done some more research on syntax - see updated question - I've still not got this to work. – coolactuary Jan 14 '15 at 09:49
  • Regarding `PopulateTableSelect`: Use [ajax](http://api.jquery.com/jQuery.ajax/) method instead of `load`. Then you don't need to wrap it with `$.Deferred` since `ajax` returns `Deferred` object anyway. – hindmost Jan 14 '15 at 10:43
  • @hindmost at the risk of turning the question into a discussion I'll post what I've tried into my question, removing it in due course if and when I have a complete answer – coolactuary Jan 14 '15 at 12:42
  • Your success callback is lacking the closing `}` – Bergi Jan 14 '15 at 13:08
  • @Bergi. Thanks. I'm not sure you're right, but I certainly messed up my "new code" markup - now updated. Does that help? – coolactuary Jan 14 '15 at 13:15

0 Answers0