Typescript - Wait for promise resolve before function return

Updated with working solution

I start with a function that grabs information from all rows selected in a table and pushes that information into a stack for later processing.

for (var i = 0; i < this.selectedItems().length; i++) { var row = this.selectedItems()[i]; let info = this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc); fileReqInfo.push(info); } 

My Problem: The createFileReqInfo function returns before the asynchronous API call can return a value, so I'm not getting the right value for userCanView in the return object.

createFileReqInfo = (reportId: number, fileRequestType: FileRequestType) : any => { let fileReq = new FileRequest(reportId, fileRequestType); var uCanView = false; this.reportModel.getReportSecurity(reportId).done((result) => { uCanView = result.CanViewReport; var info: { fileRequest: FileRequest, userCanView: boolean } = { fileRequest: fileReq, userCanView: uCanView } return info; }); } 

The compiler won't let me use await here. Any ideas on how to get the function to block until the API call returns?


Solution

My problem here is that there were a few levels of function calls here that I had to rework to create and resolve promises. The function that calls the API resembles something in the suggested solutions

createFileReqInfo = (reportId: number, fileRequestType: FileRequestType) : JQueryPromise<any> => { let fileReq = new FileRequest(reportId, fileRequestType); var uCanView = false; var info: { fileRequest: FileRequest, userCanView: boolean } = { fileRequest: fileReq, userCanView: uCanView } let dfd: JQueryDeferred<any> = $.Deferred(); this.reportModel.getReportSecurity(reportId).done((result) => { uCanView = result.CanViewReport; info.userCanView = uCanView; dfd.resolve(info); }); return dfd; } 

This now returns a promise. The problem I had is with the function that calls this one because it iterates through a list of selected items and queues up various reports to download, but only the ones that exist in that particular selection. Had to use this answer to figure out a way to wait for all the promises to resolve before continuing.

getFileReqsFromSelectedItems = (view1: boolean, view2: boolean, view3: boolean): JQueryPromise<any> => { var fileReqInfo: { fileRequest: FileRequest, userCanView: boolean }[] = []; let dfd: JQueryDeferred<any> = $.Deferred(); let promise: JQueryPromise<any>; let promiseArray: JQueryPromise<any>[] = []; for (var i = 0; i < this.selectedItems().length; i++) { var row = this.selectedItems()[i]; if( view1 && row.HasView1() ) { promise = this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc1); promiseArray.push(promise); } if( view2 && row.HasView2() ) { promise = this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc2); promiseArray.push(promise); } if( view3 && row.HasView3() ) { promise = this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc3); promiseArray.push(promise); } } $.when.apply($, promiseArray).done(function() { var promises = arguments; for (var j = 0; j < promises.length; j++) { fileReqInfo.push(promises[j]); } dfd.resolve(fileReqInfo); }); return dfd; } 

After that, it was easy to take the array of returned values and pass it to the download function.

downloadReports = () => { this.getFileReqsFromSelectedItems(this.view1Check(), this.view2Check(), this.view3Check()).then((fileReqsDetails) => { this.downloadTrialFiles(fileReqsDetails); }); } 

Whew!

1

2 Answers

For APIs that don't support promises, you can use new Promise to create a promise yourself, call resolve with the result of the async call, then you can use async/await syntax when calling it. More info on promises

interface ReportSecurityInfo { fileRequest: FileRequest userCanView: boolean } createFileReqInfo = (reportId: number, fileRequestType: FileRequestType): Promise<any> => { let fileReq = new FileRequest(reportId, fileRequestType); var uCanView = false; return new Promise((resolve, reject) => { this.reportModel.getReportSecurity(reportId).done((result) => { uCanView = result.CanViewReport; var info: ReportSecurityInfo = { fileRequest: fileReq, userCanView: uCanView } resolve(info) }); }) } // somewhere else... const info = await this.createFileReqInfo() 

I also went ahead and split out the type of info as its own interface for readability.

3

You can return promise from createFileReqInfo , then wait until it resolves

for (var i = 0; i < this.selectedItems().length; i++) { var row = this.selectedItems()[i]; let info = await this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc); fileReqInfo.push(info); } 

Or

for (var i = 0; i < this.selectedItems().length; i++) { var row = this.selectedItems()[i]; this.createFileReqInfo(row.Number(), FileRequestType.AssociatedDoc) .then(info => { fileReqInfo.push(info); }); } 

Where createFileReqInfo is defined as:

createFileReqInfo = (reportId: number, fileRequestType: FileRequestType) : Promise<any> => { return new Promise( (resolve, reject) => { let fileReq = new FileRequest(reportId, fileRequestType); var uCanView = false; this.reportModel.getReportSecurity(reportId).done((result) => { uCanView = result.CanViewReport; var info: { fileRequest: FileRequest, userCanView: boolean } = { fileRequest: fileReq, userCanView: uCanView } resolve(info); }); } } 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like