skip to Main Content

When the code runs window.location.href kicks in before all async calls to the API is done. If I set a breakpoint on the location it works fine.

How can wait until all calls are done before invoking window.location.href?

Code:

const saveInvoice = async () => {
    if (containsItems()) {
        let customerId = document.getElementById("Customer").value;
        let date = document.getElementById("Date").value;
        let dueDate = document.getElementById("DueDate").value;
        let msgKID = document.getElementById("MSG").value;
        let accountId = document.getElementById("Account").value;
        let data = await WebRequest("InvoiceAPI", "CreateInvoiceAsync", null, { "CustomerId": customerId, "Date": date, "DueDate": dueDate, "MsgKID": msgKID, "AccountId": accountId });

        getLineNumbers().forEach(async (nr) => {
            let prodId = parseInt(document.querySelector('select.prod[data-id="' + nr + '"]').value);
            let descr = document.querySelector('input.description[data-id="' + nr + '"]').value;
            let price = parseFloat(document.querySelector('span.price[data-id="' + nr + '"] > span.sum').innerHTML);
            let mva = parseInt(document.querySelector('span.mva[data-id="' + nr + '"] > span.sum').innerHTML);
            let mvaSum = parseFloat(document.querySelector('input.mva-value[data-id="' + nr + '"]').value)
            let count = parseInt(document.querySelector('input.count[data-id="' + nr + '"]').value);
            let perc = parseInt(document.querySelector('input.perc[data-id="' + nr + '"]').value);
            let sum = parseFloat(document.querySelector('#Lines > div.line.row > div.amount-wrap[data-id="' + nr + '"] span.line-sum').innerHTML);

            await WebRequest("InvoiceAPI", "CreateInvoiceLineAsync", null, { "InvoiceId": data.json.id, "ProductId": prodId, "Description": descr, "Count": count, "Discount": perc, "Price": price, "Mva": mva, "MvaSum": mvaSum, "Sum": sum });
        });

        window.location.href = "View/" + data.json.uId;
    }
    else {
        document.getElementById("InvoiceErrorWrap").classList.remove("hide");
    }
};

2

Answers


  1. You can use Promise.all to wait for an array of Promises to be completed. (Array#forEach is not designed to work with Promises.)

    Here, we can use Array#map to create an array containing a Promise for each element in the array returned by getLineNumbers().

    await Promise.all(getLineNumbers().map(async nr => {
        // other code...
        await WebRequest("InvoiceAPI", "CreateInvoiceLineAsync", null, { "InvoiceId": data.json.id, "ProductId": prodId, "Description": descr, "Count": count, "Discount": perc, "Price": price, "Mva": mva, "MvaSum": mvaSum, "Sum": sum });
    }));
    // set location here
    
    Login or Signup to reply.
  2. Each individual asynchronous operation appears to internally await, but nothing is awaiting all of those operations. More literally, saveInvoice is async but it doesn’t await anything.

    You can replace the call to .forEach() with a call to .map() to return the promises:

    const promises = getLineNumbers().map(async (nr) => {
      //...
    });
    

    Then await those promises:

    await Promise.all(promises);
    window.location.href = "View/" + data.json.uId;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search