how to enforce sequence in http requests with pipe in Angular 7

Viewed 2897

I have a component that invokes a few http requests to different url's. Each request is implemented as an observable.

getIds():Observable<any[]> {
   return this.http
    .post(url1, '')
    .pipe(map(({ Ids}: any) => Ids.map(item => ({Id: item.Id }))));
    }

getNames(data: Names):Observable<any[]> {
   return this.http
    .post(url2,element)
    .pipe(map(({ Results }: any) => Results[0].map(item => ({id: item.ID, name: item.CVSS}))));
    }

From the component, I need to do,

ngOnInit() {
  this.Ids = this.getIds();
  Ids.forEach(function(element) 
     this.getNames();
}

Can someone please show how I can enforce this order?

2 Answers

Import the switchMap from RXJS

import { switchMap } from 'rxjs/operators'

then pipe to the map on the returned observable

this.getIds().pipe(
  switchMap((id: string) => this.getNames(id))
).subscribe((response) -> {
  console.log(response)
})

getIds returns an array of Ids and you want to create an Observable (getNames) for each of the Ids. Then, you want to arrange all of the list of names together. There are several ways that you can do this, but I'll suggest one:

this.getIds().pipe(
  /*
   * mergeMap here will effectively flatten the inner Observable created by getNames.
   * This means that the next operator will get the *result* of the getNames Observable
   * rather than the Observable itself, so you don't need to subscribe to it explicitly.
   */
  mergeMap(id => this.getNames(id)),

  /*
   * This is optional. `names` is an array. `mergeMap` over an array emits each array element
   * individually. This simply flattens the collection of names arrays.
   */
  mergeMap(names => names),

  /**
   * This is also optional. It will emit the entire collection of results as an array once
   * all of the previous Observables have completed.
   */
  toArray()
)

You can subscribe to the Observable created by this to get the flattened list of names.

I would also suggest that, if possible, you add a method to your service that allows you to retrieve all names rather than having to retrieve the list of Ids first and each name per Id individually.

Related