What is the best way to implement an asynchronous function using a for loop and APIs in Typescript?

Struggling with ensuring my function returns data only after completing all API calls and the for loop.

getListingsImages(sessionID, mlsSearchCriteria){

      this.http.get(this.laconiaBaseURL + "mls/search/" + sessionID + "?" +queryString).subscribe((data)=>{

        listings = data['data'];

         for (let listing of listings) {

          postData.listingImageURL = imageBaseURL + listing.firstImage;
          postData.listingPrice = this.formatter.format(listing.ListPrice).toString();
          postData.listingMLSID = listing.listingKey;
          postData.listingAddress = listing.FullAddress;

          this.http.post(this.imageParserBaseURL, postData, {responseType: 'text'}).subscribe((data)=>{

            this.slides.push({
              data: data,
              type: "image",
              slideHeader: null,
              duration: 10
            });

          });
        }
      });
  }

Noticing two http calls, I need to ensure both listings are retrieved before progressing through the for loop. this.slides currently a global variable.

Attempted callbacks but struggling to apply them effectively in my case. How can I make sure my code waits for completion of both API calls and the For loop?

Answer №1

To convert observables into promises and implement an async/await pattern, follow this example:

async getListingsImages(sessionID, mlsSearchCriteria) {
  const data = await lastValueFrom(this.http.get(this.laconiaBaseURL + "mls/search/" + sessionID + "?" +queryString));
  listings = data['data'];
  let postDatas = listings.map(listing => Object.assign({}, postData, {
      listingImageURL: imageBaseURL + listing.firstImage,
      listingPrice: this.formatter.format(listing.ListPrice).toString(),
      listingMLSID: listing.listingKey,
      listingAddress: listing.FullAddress
    });
  let posts = postDatas
    .map(postData => this.http.post(this.imageParserBaseURL, postData, {responseType: 'text'}))
    .map(obs => lastValueFrom(obs));
  const results = await Promise.all(posts);
  const newSlides = results.map(data =>{
          data: data,
          type: "image",
          slideHeader: null,
          duration: 10
        });
  this.slides.push(... newSlides);
}

This code assumes certain behaviors such as:

  • The values added to this.slides will maintain the same order as returned in the initial request's data
  • Waiting for all results to be retrieved before updating this.slides
  • No cancellation of requests is needed
  • No restriction on concurrent requests made to imageParserBaseURL

If more advanced behavior is required, adjustments may be necessary, possibly returning an Observable instead of a Promise.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Primeng - Displaying names in editable datatable with multiSelect feature

Lately, I have been exploring primeng and I am interested in creating an editable table that includes a multi-select column. After some experimentation, I managed to achieve this result. However, my issue is that I want the winners field (which contains a ...

The switch statement and corresponding if-else loop consistently produce incorrect results

I'm currently facing an issue where I need to display different icons next to documents based on their file types using Angular framework. However, no matter what file type I set as the fileExtension variable (e.g., txt or jpg), it always defaults to ...

When assigning JSON to a class object, the local functions within the class became damaged

This is a demonstration of Object Oriented Programming in JavaScript where we have a parent Class called Book with a child class named PriceDetails. export class Book { name: String; author: String; series: String; priceDetails: Array<Price> ...

Error message on Cypress with TypeScript: No test specification files detected

Encountering the error "Unable to run because no spec files were found, even though there is a .ts spec file in Cypress. Execute the command below in the terminal: npx cypress run --spec="./cypress/integration/specs/Test1.spec.ts". Attempted to run the t ...

Ensuring that environment variables are properly set is essential for effective error handling

I am currently integrating my NodeJS and Typescript App to create new config files that utilize .env variables. If a specific variable is not set, I want to trigger an error. After setting up my config file, I encountered some errors; however, I am unsure ...

Trigger a (click) event on the MatTab in Material design

I have a dynamic loop through tabs and I want to be able to trigger a (click) event in order to load different options when a tab is selected. Is it not possible to use a simple click event on dynamically created tabs? I tried using (selectChange) on the ...

encountering an issue during the installation of a node package

Encountering this error while trying to install npm i npm ERR! While resolving: <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9bfaf5fceef7fae9b6f2f6fafcfeb6fefff2eff4e9dbabb5abb5aa">[email protected]</a> npm ERR! ...

Navigating the maze of Material UI in React with TypeScript

I have a functioning code, but I am trying to incorporate Material UI into it. However, when I replace 'input' with 'TextField', I encounter the following error: Uncaught (in promise) Error: Request failed with status code 422 at cr ...

Challenges Encountered when Making Multiple API Requests

I've encountered a puzzling issue with an ngrx effect I developed to fetch data from multiple API calls. Strangely, while some calls return data successfully, others are returning null for no apparent reason. Effect: @Effect() loadMoveList$: Obse ...

The error message "The type 'MouseEvent' is non-generic in TypeScript" popped up on the screen

Having created a custom button component, I encountered an issue when trying to handle the onClick event from outside the component. I specified the parameter type for the onClickCallback as MouseEvent<HTMLButtonElement, MouseEvent>, which is typical ...

`The Art of Curved Arrows in sigjma.js, typescript, and npm`

I have encountered an issue while trying to draw curved arrows in sigma.js within my TypeScript npm project. The error occurs on the browser/client-side: Uncaught TypeError: Cannot read properties of undefined (reading 'process') at Sigma.pro ...

Proper method for typing the generics of DatePickerProps belonging to the DatePicker component in mui-x library

I have a component called CustomDatePicker which has been configured for localization as shown below: function CustomDatePicker(props: DatePickerProps<unknown> & React.RefAttributes<HTMLDivElement>) { return ( <StyledDatePicker ...

Angular Error: The first argument has a property that contains NaN

Struggling with a calculation formula to find the percentage using Angular and Typescript with Angularfire for database storage. Encountered an error stating First argument contains NaN in property 'percent.percentKey.percentMale. The properties are d ...

Exploring Angular's nested Routing within dynamically loading Modules using a specific router-outlet reference

I am currently experimenting with nested routing while utilizing a named router-outlet for managing the routing in my side-bar navigation. Within my main module, I have loaded the nav-component which contains a named router-outlet within its template: &l ...

return to the original secured page based on the most recent language preference

I'm facing an issue with a logical redirection that needs to redirect users to the previous protected page after login. The login functionality is implemented using my custom login page and Google Credentials. Additionally, I have set up a multilingu ...

Value attribute property binding

Currently, I am diving into the world of Angular 5 and focusing on grasping the fundamentals. One concept that caught my attention is template reference variables. However, I encountered a roadblock along the way. Instead of utilizing a template reference ...

The requested property map cannot be found within the Array

I am working on a project using redux with react typescript. I have an external JSON file that contains employee data categorized by department id. To properly map the data with types in my application, I have created specific types. Check out this demo o ...

Is it feasible to select which modules to be loaded into the application?

Looking for a solution to my problem outlined in the title. For example, I am tasked with creating two separate versions of an app - one for France and one for the UK. In some areas, they require completely different implementations. Is it feasible to sw ...

Obtaining the TemplateRef from any HTML Element in Angular 2

I am in need of dynamically loading a component into an HTML element that could be located anywhere inside the app component. My approach involves utilizing the TemplateRef as a parameter for the ViewContainerRef.createEmbeddedView(templateRef) method to ...

Deploying an Angular application on Firebase is a great way to

I am facing an issue with hosting my Angular(5) project on Firebase. Although I have successfully deployed the application, when I access the project URL, it displays a default Firebase hosting screen instead of my actual Angular project. https://i.stack. ...