0

I've got this:

$("#grid tbody tr").each(function () {
    saveRow(model));
});

getAllRows();
...

The method saveRow is something like:

$.ajax(
{
    type: 'POST',
    contentType: 'application/json',
    url: "myUrl",
    data: JSON.stringify(model),
    success: function (data) {
        whatever();
    }
});

What happens is, I want to call the saveRow for each grid row that has changed and save it, and when they are all saved, call the getAllRows function.

What's currently happening is that when I call the getAllRows, not all of the saveRow's have finished causing the data to be returned half changed, half unchanged.

How do I ensure that I call the getAllRows only after the saveRow has finished for each row in the grid?

EDIT

Here's some more detail on the current implementation:

// ajax function to save individual row
function saveRow() {
    $.ajax(
    {
        type: 'POST',
        contentType: 'application/json',
        url: "myUrl",
        success: function (data) {
            whatever();
        }
    });
}

// array to store ajax functions called
var requests = [];

// function that iterates through all rows and saves them
$("#grid tbody tr").each(function () {
    // adding the ajax function call to the array
    requests.push(saveRow());
});


...

// supposedly, call getAllRows when all the saveRow ajax calls are done
$.when.apply($, requests).then(function () {
    getAllRows();
});

This is not working, the getAllRows is called before all the other ones finished

chiapa
  • 4,362
  • 11
  • 66
  • 106
  • You need to track how many requests you're sending off, add your results somewhere, and not process until all of them are done. Ideally you also track which ones are done and which need to be done, so you can redo the ones that fail after x time. – Jake Rowsell Jan 26 '16 at 16:43
  • 2
    Research PROMISE here - it is built into the jQuery ajax and the jQuery deferred handles this situation – Mark Schultheiss Jan 26 '16 at 16:45
  • Also add "asyn": false in ajax call. – Naqash Malik Jan 26 '16 at 16:46
  • 3
    @Malik Synchronous requests (outside of webworkers) [are being deprecated](https://xhr.spec.whatwg.org/#sync-warning). – James Thorpe Jan 26 '16 at 16:47
  • Possible duplicate of [Using $.Deferred() with nested ajax calls in a loop](http://stackoverflow.com/questions/13951456/using-deferred-with-nested-ajax-calls-in-a-loop) – Mark Schultheiss Jan 26 '16 at 16:47

3 Answers3

3

The ajax function will provide you a promise object. If you pass those promises to the JQuery $.when function, it will return another promise that will resolve when every promises you've passed will resolve:

var promise1 = $.ajax({ /* your saveRow ajax */});
var promise2 = $.ajax({ /* your saveRow ajax */});

$.when(promise1, promise2).done(function(promise1, promise2) {
    getAllRows();
});

If you have multiple safeRow ajax to wait for, you can also use the apply function to provide an array of promises to the when function:

var promises = [];
promises.push($.ajax({ /* your saveRow ajax */}));
promises.push($.ajax({ /* your saveRow ajax */}));
//...

$.when.apply($, promises).done(function() {
    getAllRows();
});
The_Black_Smurf
  • 5,178
  • 14
  • 52
  • 78
  • That's a promising option but, I don't know how many rows are to be changed. So, how could I define an unknown amount of promises? – chiapa Jan 26 '16 at 16:57
  • I updated the answer to include an example with a promises array. – The_Black_Smurf Jan 26 '16 at 17:10
  • Thanks man, I had reached exactly that just before you updated your answer. I'm still getting some weird behaviour though... It may be something else. I'll get back to you – chiapa Jan 26 '16 at 17:18
  • I'm going mad here, the `getAllRows` is called before every `saveRow` is complete. When I update 5 rows, the grid updates 2 or 3 records... Using the browser inspector, I can see the `getAllRows` being executed before all the others finish. This **should** work, damn – chiapa Jan 27 '16 at 11:51
  • Can you update your question will your current implementation? – The_Black_Smurf Jan 27 '16 at 13:41
  • Updated my question with more details on the implementation. Why the hell is this happening? Everywhere I looked, this seems the right solution, this should really cover the "wait for ajax calls to be done and then do something" thing – chiapa Jan 28 '16 at 10:42
  • The `saveRow` doesn't return anything. Should be `return $.ajax({...})` – The_Black_Smurf Jan 28 '16 at 12:31
  • Thanks, I was missing the return ajax... that's why it wasn't working! – chiapa Jan 29 '16 at 11:48
0

You could do something with promises like

var d1 = $.ajax({...});
var d2 = $.ajax({...});

$.when(d1, d2 );
.then(function() {
    ...
})
armonge
  • 3,108
  • 20
  • 36
0

If async function do not work - you could try using a variable as a condition, i.e.

If you have 10 saveRows to call, let a global variable be saveRowsRun = 0. At the end of each SaveRow function set saveRownsRun++ Have the function getAllRows() run at the end of each saveRows function, but inside an if statement;

if(saveRownsRun == 10){
    getAllRows();
}

That would ensure if tries to fire after each row, but is only able to fire after the last row.

Matthew Lymer
  • 992
  • 6
  • 10
  • Yeah, but that if would be skipped way before the variable == 10, so it would never call getAllRows – chiapa Jan 26 '16 at 16:59
  • As I said, the code I proposed would exist at the end of EVERY saveRows() function - so it will attempt to call it every time, but only succeed the 10th time (when the if condition has been met). – Matthew Lymer Jan 26 '16 at 17:34