Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle multiple http requests and wait for all to complete using Angular RxJs Observables

I am using Observables, I have a use case where:

  1. I have to get "pages" from service which gives me Page[]
  2. For each of those "pages" I have to get the "sections" from other service
  3. Also on subscribe of all those "sections" I have to do some action based on the data returned.

The concern is once all of those requests are completed then have to do some action.

like image 415
Avneesh Avatar asked Jun 28 '17 03:06

Avneesh


People also ask

What is the use of forkJoin in Angular?

Why use forkJoin ? This operator is best used when you have a group of observables and only care about the final emitted value of each. One common use case for this is if you wish to issue multiple requests on page load (or some other event) and only want to take action when a response has been received for all.


2 Answers

you need use mergeMap and forkJoin

When using forkJoin you can fire parallel request at the same time and it will wait till all requests are completed.

this.http.get('/api/pages/')
    .map((res: any) => res.json())
    .mergeMap((pages: any[]) => {
      if (pages.length > 0) {
        return Observable.forkJoin(
          pages.map((page: any) => {
            return this.http.get('/api/sections/' + page_id)
              .map((res: any) => {
                let section: any = res.json();
                // do your operation and return
                return section;
              });
          });
        );
      }
      return Observable.of([]);
    });
}
like image 154
CharanRoot Avatar answered Dec 12 '22 15:12

CharanRoot


In general when nesting async calls try to stay as flat as possible. Otherwise, you're creating callback hell which make things even more complicated than just with regular iterative code:

this.http.get('/api/pages/')
  .map((res: Response) => res.json())
  .concatMap((pages: Page[]) => {
    const observables = pages.map(p => this.http.get('whatever' + p.id));

    return Observable.forkJoin(observables, (...results) => 
      results.map((result, i) => {
        pages[i].sections = result;
        return pages[i];
      })
    )
  })
  .subscribe(pagesWithSections => ...);

The forkJoin() operator takes as argument a selector function that lets you work with the results of all the source Observables. I'm using it to update the original pages array and return it.

like image 39
martin Avatar answered Dec 12 '22 15:12

martin