Reputation: 5174
This is a restatement of the problem I was experiencing in my previous question, I think that question suffered from the X,Y problem. I hope this question gets closer to the heart of the issue I'm experiencing. See scchange.js on Github for code.
I have an array of deferred jQuery objects that I'm calling $.when
on. These are the functions that send POST requests to the server that modify data. The $.when
call is wrapped in a $.get
callback. This requests the data fields that I'm about to modify, satisfying the authorization requirement. Here's the code:
$.get('/admin/students/contacts/scchange/phoneTlcForm.html?frn=001' + studentsdcid, function () {
console.log('get callback reached');
$.when.apply($j, phoneAjaxCalls).done(function () {
console.log('phoneAjaxCalls promises resolved');
returnToStudentContacts();
});
});
I am using phoneAjaxCalls.push(newPhone(tlcPhone,studentsdcid))
to push ajax calls to the array, and newPhone returns an ajax deferred object:
function newPhone(tlcPhone, studentsdcid) {
//Create new phone
return function() {
return $j.ajax({
type: 'POST',
url: '/admin/changesrecorded.white.html',
data: tlcPhone
});
};
}
When this code is run, I see in the Console that "get callback reached" is printed before "phoneAjaxCalls promises resolved", which suggests that the requests are getting sent in the order that they are shown in the code. However, Chrome's DevTools Network tab seems to suggest that the phoneAjaxCalls network requests are getting completed before the phoneTlcForm.html
document is loaded.
The first 6 requests are all phoneAjaxCalls
requests, and the last request is phoneTlcForm.html
from the $.get
, but that should be first!
It appears that the backend is receiving these requests in the same order as the Network tab is showing, because I'm getting authorization errors in the responses to those phoneAjaxCalls
requests.
What needs to happen is that the request to phoneTlcForm.html
should complete before any of the phoneAjaxCalls
requests are made.
My project is a plugin, so I can't modify the backend logic to make this process easier. The system that I'm interfacing with has certain authorization requirements when creating or updating data. The backend system must "see" that the data fields that I want to modify were rendered in an HTML page before the requests that modify data are sent. This is why I need the phoneTlcForm.html
page to load before the other requests.
Upvotes: 1
Views: 214
Reputation: 5348
What's happening here is that when you build the phoneAjaxCalls
array, you call to $j.ajax
for each individual item. Each request will be made as soon as you do that call.
I guess that by the time you call $j.when.apply($j, phoneAjaxCalls)
, most of the promises there will be already resolved, and the done callback called right away.
Let me try to illustrate with some comments:
// previous ajax requests already fired!
$j.get('/admin/students/contacts/scchange/phoneTlcForm.html?frn=001' + studentsdcid, function () {
console.log('get callback reached');
// inspect the state of phoneAjaxCalls here
// they might be resolved already.
// you want to exec those ajax calls here, not before!
$j.when.apply($j, phoneAjaxCalls).done(function () {
console.log('phoneAjaxCalls promises resolved');
returnToStudentContacts();
});
});
So from here you have differents way to solve it. I think you already got a good response in the question you linked.
In each place you return $j.ajax, you could return a function wrapping that instead, to avoid the execution. Let's take the updateEmail function as an example:
return function(){
return $j.ajax({
url: '/ws/schema/table/' + config.contactsEmailTable + '/' + emailRecordId,
data: JSON.stringify(emailUpdateData),
dataType: 'json',
contentType: "application/json; charset=utf-8",
type: 'PUT'
});
};
After wrapping all those, you can call them like this:
$.get('/admin/students/contacts/scchange/phoneTlcForm.html?frn=001' + studentsdcid, function () {
var phoneAjaxCallsPromises = $.map(phoneAjaxCalls, function(c){
return c();
});
$.when.apply($j, phoneAjaxCalls).done(function () {
console.log('phoneAjaxCalls promises resolved');
returnToStudentContacts();
});
});
This solution feels like a hack, but understanding the problem might enable you to implement the proper fix.
Upvotes: 2