Populating a Form Using Promises or Async/Await

I'm trying to populate a form using JavaScript promises or async/await (or similar) but just can't seem to get it. I tried .then and Promise.all with the same result: if one of the "get" functions takes longer than the getPunchlistItem function, the actual value is overwritten.

var myFSEs = [];
var myTypes = [];
var myPeople = [];

$(document).ready(function () {
  getFSEs("itemFSE", "Select FSE...")
    .then(getPersons("itemResponsible", "Select Person..."))
    .then(getTypes("itemType", "Select Type..."))
    .then(getPunchlistItem(myPLItemID));
 //or
  Promise.all([getFSEs("itemFSE", "Select FSE..."), getPersons("itemResponsible", "Select Person..."), getTypes("itemType", "Select Type...")]).then(function () {
    getPunchlistItem(myPLItemID);
  });
});

Open in new window


My async functions look like:

async function getFSEs(el, allText, filter) {
   let result = await getJson(myURL + "PunchlistTracking/_api/web/lists/getbytitle('FSEs')/items", function (data) {
   myFSEs = data.d.results.map(FSE => [`${FSE.Id}`, `${FSE.Title}`, `${FSE.FSEName}`]);
   var output = `<option value='0' selected='selected'>${allText}</option>`;

    for (var i = 0; i < myFSEs.length; i++) {
        if (`${myFSEs[i][3]}` == filter || !filter) {
            output += `<option value='${myFSEs[i][0]}'>${myFSEs[i][1]} ${myFSEs[i][2]}</option>`;
        }
    };

    $(`#${el}`).html(output);
    }, logError);

    return result;
}

function getJson(endpointUrl, success, failure) {
  $.ajax({
    type: "GET",
    headers: {
        "accept": "application/json;odata=verbose",
        "content-type": "application/json;odata=verbose"
    },
    url: endpointUrl,
    success: success,
    failure: failure
  });
}   //  getJson

Open in new window


Form Population Issue
LVL 11
Michael VasilevskySolutions ArchitectAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Julian HansenCommented:
Can you explain rather what you are trying to get your form to do?
0
Michael VasilevskySolutions ArchitectAuthor Commented:
Sure, I want to populate the dropdowns (FSE, Type, and Responsible) via functions like getFSEs, and then populate the form fields with the values specific to the item selected on the previous page. My issue is sometimes the getFSEs, getTypes, or getResponsible dropdowns are populated after the form is populated with specific values. I'm trying to resolve that issue by using async await. With the above code sometimes the dropdowns are still populated after the form, and I'm not understanding why.

Let me know if you need more detail!
0
Julian HansenCommented:
Async is not totally cross platform yet and I am not sure await is what you want here?

Await is going to wait for your request to complete before it returns. From what I can tell you want to populate your drop downs asynchronously - but your implementation has me a bit confused - for instance
I read this as
 Promise.all([getFSEs("itemFSE", "Select FSE..."), getPersons("itemResponsible", "Select Person..."), getTypes("itemType", "Select Type...")]).then(function () {
    getPunchlistItem(myPLItemID);
  });

Open in new window

Only get the Punch List Item when the other (getFSE, getPersons, getTypes) have resolved - so I need more info as to what your form is doing and how you want that to come across to the user.

Must the form be inaccessible until those items have populated?
0
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

Michael VasilevskySolutions ArchitectAuthor Commented:
This code is populating the form for editing existing data. I open the page, populate the dropdowns dynamically, and then populate the existing data. Then the user can edit the data and send it back the server.

I want getPunchlistItem to be called only after getFSEs, getPersons, and getResponsible have resolved.
0
Julian HansenCommented:
Is there a reason you are making multiple calls to get the data? Is it being sorced from different locations?

If not I would make one call - get the data in a single shot and popluate the form in one go.
1
Michael VasilevskySolutions ArchitectAuthor Commented:
Yes these are separate REST calls to individual SharePoint lists.
0
Michael VasilevskySolutions ArchitectAuthor Commented:
Here is the solution I came up with:

var myFSEs = [];
var myTypes = [];
var myPeople = [];

$(document).ready(function () {
    (async () => {
        await getFSEs("FSEs", "All FSEs");
        await getPersons("Persons", "All Personnel");
        await getTypes("itemType", "Select Type...");
        getPunchlistItem(myPLItemID);
    })()    //  async
});

Open in new window


where my "get" functions look like:
function getFSEs(el, allText, filter) {
    return new Promise(function (resolve) {
        getJson(myURL + "PunchlistTracking/_api/web/lists/getbytitle('FSEs')/items", function (data) {
            myFSEs = data.d.results.map(FSE => [`${FSE.Id}`, `${FSE.Title}`, `${FSE.FSEName}`]);
            var output = `<option value='0' selected='selected'>${allText}</option>`;

            for (var i = 0; i < myFSEs.length; i++) {
                if (`${myFSEs[i][3]}` == filter || !filter) {
                    output += `<option value='${myFSEs[i][0]}'>${myFSEs[i][1]} ${myFSEs[i][2]}</option>`;
                }
            };

            $(`#${el}`).html(output);
            resolve();

        }, logError);
    });
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Julian HansenCommented:
Glad you got an answer however I don't think the one you have is the best approach.
The await's in your code are going to block - if each of those calls takes 2 seconds your app is going to wait 8 seconds for all of them to complete.

If it were me I would make a new server side REST endpoint that fetches all the data at once and sends it back as a single response.
0
Michael VasilevskySolutions ArchitectAuthor Commented:
Thanks for the comment Julian. This is SharePoint Online so I’m limited to the endpoints provided by Microsoft.
0
Julian HansenCommented:
Is it not possible to wrap them server side in your own REST endpoint? SP not my strong point so just putting this out there in case it is useful.
0
Michael VasilevskySolutions ArchitectAuthor Commented:
We can’t do anything server side with SharePoint Online. Makes for some interesting development situations :)
0
Julian HansenCommented:
Ok understood.
0
Michael VasilevskySolutions ArchitectAuthor Commented:
Solved it!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
JavaScript

From novice to tech pro — start learning today.