dextercom
dextercom

Reputation: 162

Loop over typescript Array asynchronously

I have a typescript array this.products I need to loop over the elements of the array and for each element send parameters to Angular service which makes an API call and gets an answer to the client as an Observable. However, due to asynchronous nature of Observable, my loop finishes before all of the answer are sent back from the server. This is my code:

this.products.forEeach((ele, idx) => {
     this.myService.getSomeDetails(ele.prop1, ele.prop2).subscribe(result => {
         // do something with result 
     });   
});

I need for the loop to advance only after the completion of each observable subscription. How can I implement it? Thanks.

Upvotes: 1

Views: 2262

Answers (4)

Maksim Romanenko
Maksim Romanenko

Reputation: 365

This is good way to code it.

from(this.products).pipe(mergeMap(
     ele => this.myService.getSomeDetails(ele.prop1, ele.prop2)
)).subscribe(result => {
     () => console.log('.'),
      e => console.error(e),
     () => console.log('Complete')
});

Upvotes: 0

Kamil Kiełczewski
Kamil Kiełczewski

Reputation: 92677

Try this:

let results = await Promise.all(this.products.map(ele => 
    this.myService.getSomeDetails(ele.prop1, ele.prop2).toPromise()
));

// put code to process results here

Requests are sent parallel. Rememeber to add async keyword in function definition which use above code. More info here.

Upvotes: 0

Davy
Davy

Reputation: 6441

What you are looking for is forkJoin:

https://rxjs-dev.firebaseapp.com/api/index/function/forkJoin

Map your array of items to an array of api call observables, and pass them into forkJoin. This will emit an array of all your resolved api calls.

Quick and dirty example:

forkJoin(this.products.map(i => this.myService.getSomeDetails(ele.prop1, ele.prop2))).subscribe(arrayOfApiCallResults => {
    // get results from arrayOfApiCallResults
})

Upvotes: 4

user4676340
user4676340

Reputation:

You don't need async/await keywords to make your call in sequence.

import { concat } from 'rxjs';

concat(this.products.map(ele => this.myService.getSomeDetails(ele.prop1, ele.prop2)))
  .subscribe(
    response => console.log(response),
    error => console.log(error),
    () => console.log('all calls done')
  )

Upvotes: 2

Related Questions