Answered by:
jQuery Promises and async calls

Question
-
User438705957 posted
I have read that synchronous $.ajax calls will eventually be deprecated, so I am changing all my calls to asynchronous.
The JavaScript code I have is looping thru an EF model type, identifying which fields are foreign key fields, and building a select/option drop-down that contains the foreign table key and value by linking out to the foreign table in an ajax async call.........simples.
To do this I am building an array of deferred jQuery promises based on the number of foreign keys in the current model type. Once each promise is completed (promise.Done()), the code kicks in to build the select element.Pseudo code is:
For each foreign key
var getForeignCollection = getForeignTableData(foreign key field); // create promise
deferreds.push(getForeignCollection); // push promise to array
getForeignCollection.Done({ // On completion of every promise.
build select element
})
End loop of foreign keys
When all promises are resolved, I employ a $.when.apply($, deferreds) to show a modal with all the drop downs, and also to handle failure.
$.when.apply($, deferreds)
.then(function () { // success in all the deferred promises
Show modal,
function (jqXHR, textStatus, err) { // failure in one of the deferred promises
Handle failure
} });The problem is the first set of promises in the deferreds array son't seem to be clearing on subsequent calls involving other model types.
I am trying to figure out a way to clear/reject the original set of promises for each type.
If I do a call to the database between calls to this code, it clears itself?Thanks for considering.
Monday, February 25, 2019 10:27 PM
Answers
-
User-474980206 posted
you can only call resolve or reject on the differed, not the promise. you should never be trying to force this. this code:
$.when.apply($, deferreds) .then(function () { // success in all the deferred promises deferreds = []; getForeignCollection.abort; $('#modalUpdate').modal({ backdrop: 'static', keyboard: false }); },
makes no sense. the then will only be called after the all the promises in the defereds array have called resolve. there is nothing to abort. also not sure the point of clearing the array.
note: when you use when().then() with more than one promise, then is only called once, with the values of the first resolve (if all resolve). or first reject (if any reject).
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Wednesday, February 27, 2019 4:41 PM
All replies
-
User839733648 posted
Hi Madog,
For each foreign key
var getForeignCollection = getForeignTableData(foreign key field); // create promise
deferreds.push(getForeignCollection); // push promise to array
getForeignCollection.Done({ // On completion of every promise.
build select element
})
End loop of foreign keysWhere do you call this function? I think it may affect the result.
And from the codes using $.when.apply($, deferreds), there seems no any codes to clear the model types already set.
Maybe you could try Promise .resolve().
$.when.apply($, deferreds)
.then(function () { // success in all the deferred promises
Show modal,
function (jqXHR, textStatus, err) { // failure in one of the deferred promises
Handle failure
} });I'm also curious about how do you show the modal. What is it content?
Best Regards,
Jenifer
Tuesday, February 26, 2019 8:38 AM -
User-474980206 posted
you are building you promise collection, of before done(), try:
var deferreds = []; for (....) { var getForeignCollection = getForeignTableData(foreign key field).then( function(r) {...}, function(r) {...} ); // push then promise deferreds.push(getForeignCollection); } $.when.apply($, deferreds) .then( .... ) .catch( .... );
Tuesday, February 26, 2019 4:02 PM -
User438705957 posted
Hi Jenifer,
The foreign key loop is contained in a function called buildUpdateModal().
This function is called from a click event on an update button at the end of each table row (which is also built in jQuery/JavaScript)$(document.body).on("click", "tbody tr .update", function () { cleanUp(); $('#modalUp').text("Update"); buildUpdateModal($tr); });
I just posted the pseudo code for the $.when.apply($, deferreds). Here is the full code with the statement to display the modal.
The modal contains all the dropdowns for the foreign keys, as well as other fields that are not foreign keys.$.when.apply($, deferreds) .then(function () { // success in all the deferred promises deferreds = []; getForeignCollection.abort; $('#modalUpdate').modal({ backdrop: 'static', keyboard: false }); }, function (jqXHR, textStatus, err) { // failure in one of the deferred promises if (!validationFail) { errorCallback(jqXHR, textStatus, err); // call error routine problemPromise(); // disable all clickable controls } throw "Error"; });
I tried getForeignCollection.resolve() in the $.then and also in the $.when.
It doesn't appear that Resolve() is a method property of a jQuery promise and it fails.Thanks for responding
Tuesday, February 26, 2019 11:19 PM -
User-474980206 posted
you can only call resolve or reject on the differed, not the promise. you should never be trying to force this. this code:
$.when.apply($, deferreds) .then(function () { // success in all the deferred promises deferreds = []; getForeignCollection.abort; $('#modalUpdate').modal({ backdrop: 'static', keyboard: false }); },
makes no sense. the then will only be called after the all the promises in the defereds array have called resolve. there is nothing to abort. also not sure the point of clearing the array.
note: when you use when().then() with more than one promise, then is only called once, with the values of the first resolve (if all resolve). or first reject (if any reject).
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Wednesday, February 27, 2019 4:41 PM -
User438705957 posted
Bruce, I'm going to have a go at your form of the code as per your post above, after it stops hitting the fan here.
The clearing of the deferreds array and the abort were just stabs at it.
I understand the .then is called after all the promises in the array have called resolve, which is what I want.
Thanks for responding
Thursday, February 28, 2019 9:45 PM -
User438705957 posted
Ok, So I have it working as expected and how I want.
The array of deferreds is filled. I then employ a $.when.apply to proceed once all the promises in the array of deferreds have been resolved.
if ($tr.data("pathway") && $tr.data("pathway").left(10) === "Adding mtm" && dbField === "Audit_Measure_Task") { deferreds.push(buildMeasuresNotAdded($tr, objModel)); // Retrieve Audit Measure Tasks not yet added for the audit and build a select element } else { deferreds.push(buildForeignTableSelects(dbField,$tr,objModel)); // Retrieve the foreign collection table for the current foreign key and build a select element }
$.when.apply($, deferreds) // all promises in the array of deferreds have been resolved one way or the other - show the update modal .then(function () { $('#modalUpdate').modal({ backdrop: 'static', keyboard: false }); }) .fail(function (jqXHR, textStatus, err) { // failure in one of the promises if (jqXHR.status == 417) { //417 is ExpectationFailed - this is set by the controller method errorCallback("Failure", "Failure", jqXHR.responseJSON.CustomErrorMessage); } else { errorCallback(jqXHR, textStatus, err); problemPromise(); // disable all clickable controls } });
Each promise in the deferred array has it's own $.Done to process the results of that particular promise.
I am capturing any failures in the outer .fail under the $.when.As Bruce has said, you can't set the status of a promise yourself
Hope that makes sense.Monday, March 25, 2019 3:08 AM