javascriptjqueryajaxjquery-deferredjquery-ajax

Deferred jquery ajax


I've looked through all the issues on this, I think.

I have a function which uses jquery to update a record via ajax. I need to change it to do them and wait for each one to finish.

I've been reading about $.Deferred and have tried to implement, but the code still doesn't wait. I understand that ajax is asynchronous and I don't want to change that as such, but I do want it to wait, as the code outputs messages and I need them in order.

My code is as such:

//do the export:
function doExport(id) {

var exportComplete = $.Deferred();

var exportPromise = $.ajax({
    type: "POST",
    url: "import.php",
    dataType: "json",
    data: { id: id }
});

exportPromise.done(function(msg) {
    //msg contains the text from the import
    exportComplete.resolve(msg);
});

return exportComplete.promise();
}

//export all ticked items (from a list)
function importInvoices() {

    var checked = new Array;
    $('#apiCall').html("");

    //put all checked items into an array (id corresponds to a PK in the db)
    $("input[name=selectedRow]:checked").each(function(num,row) {
        checked.push($(row).data('id'));
    });

    //loop through each checked item
    $(checked).map(function(num, id) {
console.log("starting " + id)            ;
        var prom = doExport(id).then(function(result) {
console.log("done " + id);
            
            $('#apiCall').html($("#apiCall").html() + result.messages);
        
        });
    });

    $("#pleaseWaitContainer").hide();

}

It must be so close, but I guess I've got something missing or in the wrong place. The text from the resulting export does appear where it should, but if (for example) I select 3 invoices, I get the console text of "starting xxx" 3 times, and then the "done xxx" four times.

Like this:

starting 243
starting 663
starting 823
done 243
done 663
done 823

Whereas what I want is

starting 243
done 243
starting 663
done 663
starting 823
done 823

Any advise would be lovingly appreciated... I'm tearing my limited hair out.

Chris


Solution

  • Call in Success

    const checked = $("input[name=selectedRow]:checked").map(function() {
      return $(this).data('id'))
    }).get()
    const load = function() {
      $.ajax({
        url: `/someprocess.php?id=${checked.shift()}&otherparm=bla`,
        success: function() {
          if (checked.length > 0) load()
        }
      })
    }
    
    if (checked.length > 0) load(); // start