keschra
keschra

Reputation: 338

Rxjs mergeMap: Concat 2 related Api Requests

I have two api requests, the second one depends on the first one. The first request gets an array of 3 facilities. After this i need to do an api request for each facility to get an image which i need. I need the uuid of the facilities. I thought this could be easy with mergeMap. But i have 2 problems and can't find a solution: inside merge map, i thought service will be one service of the array but it is the whole array. Also I need to subscribe to getImage() too and store the value inside service.image.

getNewestNursingServices() {
  return this.http.get('api/nursing-service/newest').pipe(
   mergeMap(service => this.getImage('PREVIEW', service.uuid))
  );
}
getImage(type: string, nursingService: string): Observable<Image> {
  return this.http.get<Image>('api/nursing-images/' + type + '/' + nursingService);
}

Upvotes: 1

Views: 2862

Answers (2)

Alex Biro
Alex Biro

Reputation: 1227

I hope I got the question right.

So your first problem was that the first api call returns an array. That can be solved by mergeMap-ing the flattened array, so the downstream observable will emit the 3 services consecutively.

getNewestNursingServices() {
  return this.http.get('api/nursing-service/newest')
    .pipe(
      mergeMap((services: []) => {
        // `of` will return an observable which emits the items of the array after each other
        return of(services);
      }),
      mergeMap(service => this.getImage('PREVIEW', service.uuid)),
      tap((image: Image) => {
        // here you can do sideeffects with the images, eg. pushing them into an array somewhere...
      }),
      reduce(
        (allImages: Image[], currentImage: Image) => {
          // ... or you can collect them into an array, so the downstream will be `Observable<Image[]>`
          allImages.push(currentImage);
          return allImages;
        },
        [],
      ),
    );
}

Regarding the fact that you have to subscribe, that's not true, you can use the resulting observable for example in an async pipe, if you don't want to do the sideeffect+subscription pattern.

Upvotes: 0

Julius Dzidzevičius
Julius Dzidzevičius

Reputation: 11000

You can use forkJoin or concat:

getNewestNursingServices() {
  return this.http.get('api/nursing-service/newest').pipe(
   mergeMap((service: any[]) => {
     return concat(...service.map(s => {
       return this.getImage('PREVIEW', s.uuid)
     }) 
   }) 
  );
}

Upvotes: 3

Related Questions