How do I use $.when
in JQuery with chained promises to ensure my ajax requests are completed in the right order?
I have an array called costArray
which is made up of a number of dynamic objects. For each item in this array, I'll call an Ajax request called GetWorkOrder
which returns a WorkOrder
which is basically a table row element with the class .workOrder
and appends it to the table with id #tbodyWorkOrders
.
Once all the items in the array are processed, I use $.when
to let me know when I can calculate the SubTotal
of each WorkOrder
.
My problem is that my WorkOrder
s are being inserted in random orders, as the ajax requests are being processed async. How can I ensure my ajax requests are processed and appended in the correct order?
i = 0;
$.each(costArray, function (key, value) {
var d1 = $.get('/WorkOrders/GetWorkOrder', { 'i': i }, function (html) {
$('#tbodyWorkOrders').append(html);
$('.workOrder').last().find('input').val(value.Subtotal);
});
$.when(d1).done(function () {
SetSubtotal();
i++;
});
Edit:
costArray is taken from an earlier ajax call and is an array of items that I am inserting into the table rows:
var costArray = JSON.parse([{"Trade":"Plasterer","Notes":"Test","Subtotal":"3781.00"}]);
The line:
$('.workOrder').last().find('input').val(value.Subtotal);
is one of many that takes the values from GetWorkOrder and puts them into the correct inputs, but I've left out the extra code for clarity
jQuery provides several methods for AJAX functionality. With the jQuery AJAX methods, you can request text, HTML, XML, or JSON from a remote server using both HTTP Get and HTTP Post - And you can load the external data directly into the selected HTML elements of your web page!
The “open” method has three parameters. The first parameter is the approach of sending HTTP request, and it has to be within GET, POST or HEAD. The second one is URL. And the third one is the sign of whether the request is to be carried out in an asynchronous mode.
ajax({ type: "POST", url: 'test. php', data: {"type":"check"}, success: function(response){ alert(response); } }); There can obviously be more key-val pairs in data. In this case your alert should read: "The type you posted is check".
get() executes an Ajax GET request. The returned data (which can be any data) will be passed to your callback handler. $(selector). load() will execute an Ajax GET request and will set the content of the selected returned data (which should be either text or HTML).
$.when()
processes all the promises you pass it in parallel, not sequential (since the async operations have already been started before you even get to $.when()
).
It will collect the results for you in the order you pass the promises to $.when()
, but there is no guarantee about the execution order of the operations passed to it.
What I would suggest is that you collect all the results (in order), then insert them in order after they are all done.
I've tried to restructure your code, but it is not clear what items form costArray
you want to pass to your Ajax call. You weren't passing anything from costArray
in your code, but the text of your question says you should be. So, anyway, here's a structural outline for how this could work:
var promises = costArray.map(function (value, index) {
// Fix: you need to pass something from costArray to your ajax call here
return $.get('/WorkOrders/GetWorkOrder', { 'i': value });
});
$.when.apply($, promises).done(function() {
// all ajax calls are done here and are in order in the results array
// due to the wonders of jQuery, the results of the ajax call
// are in arguments[0][0], arguments[1][0], arguments[2][0], etc...
for (var i = 0; i < arguments.length; i++) {
var html = arguments[i][0];
$('#tbodyWorkOrders').append(html);
}
SetSubtotal();
});
Wrap it in a function and recall it from your ajax success:
ajax(0);
function ajax(key) {
$.get('/WorkOrders/GetWorkOrder', {'i' : key },
function (html) {
$('#tbodyWorkOrders').append(html);
$('.workOrder').last().find('input').val(costArray[key].Subtotal);
SetSubtotal();
key++;
if (key < costArray.length)
ajax(key);
});
}
Edit: On further consideration, while this is one way to do it, it entails the ajax calls executing only one at a time, which isn't very time efficient. I'd go with jfreind00's answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With