0

my issue appears similar to this one but I haven't been able to resolve it with those answers.

In short, at page load an ajax call generates a dropdown select element, then its default value is set depending on some parameters.
The code goes something like this:

getList('country', null, q, 'category:customer', null);  
newReportSelection.apply($("#report"));  

function getList(field, val, q, fq, default_value) {
    $.get(... {  
      // call info
    },  function(result) {
      // appending the dropdown to DOM
    });
};

newReportSelection = function () {
    // determine and select default option
}  

getList is used at various places so I can't add this (specific to page load) newReportSelection() code to the ajax callback function.
Putting a promise around the getList() call doesn't wait for the Ajax call since it's asynchronous.
Putting one around the Ajax call waits for it to be sent, but not for the callback function to be executed.
Putting one around the callback function doesn't work either, as the Ajax part waits for it but getList() kept going because of the asynchronicity.

Even if chaining promises on the Ajax call and the callback function worked, that'd look like a pretty dirty workaround and undesirable.
Is there a way for me to make the newReportSelection() call wait until the whole getList() is done, without manually setting the Ajax calls to async: false?

Thanks in advance.

David
  • 27
  • 1
  • 6
  • 1
    Just call newReportSelection() inside your ajax done function that appends to DOM? – juvian May 23 '17 at 16:24
  • As I mentioned, I can't because the getList() function is called in several places and the newReportSelection() part is only applicable in one of these cases. – David May 23 '17 at 16:27
  • what about providing a new parameter in your getList function that is the callback you want to trigger and call that function inside the result callback? and if that is used somewhere else, just check if you passed a callback inside your result function, if so execute the callback otherwise skip the callback – quirimmo May 23 '17 at 16:28
  • That would probably work but wouldn't be as elegant (especially for the other calls, although you can omit parameters). freedomn-m's answer below solves the issue without impacting other calls and flows better with the asynchronicity. Thanks for suggesting it tho! – David May 23 '17 at 17:05

2 Answers2

3

Return the deferred/promise from $.get

function getList(field, val, q, fq, default_value) {
  return $.get(... {  
    // call info
  },  function(result) {
    // appending the dropdown to DOM
  });
};     

then you can call your followup in the promise .done() method:

getList('country', null, q, 'category:customer', null).done(function() {
    newReportSelection.apply($("#report")); 
});
freedomn-m
  • 27,664
  • 8
  • 35
  • 57
  • 1
    Was about to write this :) – juvian May 23 '17 at 16:44
  • That did the trick, thank you very much! I'm not too used to promises yet and didn't realise you could pass them around this way to keep track of them. – David May 23 '17 at 17:03
0
var d1 = $.Deferred();
var d2 = $.Deferred();
var d3 = $.Deferred();

$.when( d1, d2, d3 ).done(function ( v1, v2, v3 ) {
  console.log( v1 ); // v1 is undefined
  console.log( v2 ); // v2 is "abc"
  console.log( v3 ); // v3 is an array [ 1, 2, 3, 4, 5 ]
});

d1.resolve();
d2.resolve( "abc" );
d3.resolve( 1, 2, 3, 4, 5 );

extract from https://api.jquery.com/jquery.when/

Eduard Void
  • 2,646
  • 1
  • 13
  • 13
  • From what I understand, this applies when you execute several promises side-by-side and want all of them to be resolved before moving on. In my case they are consecutive (ajax call, when done callback, when done the other function) so this doesn't work here, unless I got it wrong? – David May 23 '17 at 16:38
  • The accepted answer looks better, but I was meaning something like this: $.when(getList(....)).done(function() { newReportSelection.apply($("#report")); }); – Eduard Void May 24 '17 at 06:04
  • I had tried it ("putting a promise around the getList() call") and that way it was considered done as soon as the function exited, eg. as long as it sent the ajax request but without waiting for it to finish. That's why returning the request's promise (from the accepted answer) works better, although I'm still not sure why putting the promise around the ajax call inside the function didn't wait for the callback to end too. – David May 24 '17 at 07:43