Search code examples
angularrxjsconcatmap

How to properly chain concatMaps in Angular RxJS


    this.route.params.pipe(
      concatMap((param) => {
        const ein = param['nonprofit-id'];
        return this.nonprofitService.getNonprofit(ein).pipe(
          concatMap((nonprofit) => {
            this.nonprofit = nonprofit;
            const ratingID = nonprofit.currentRating?.ratingID ? nonprofit.currentRating.ratingID : -1;
            return this.nonprofitService.getRatingForNonprofit(ein, ratingID).pipe(
              concatMap((nonprofitRating) => {
                this.nonprofitRating = nonprofitRating;
                const causeID = this.nonprofit?.cause?.causeID ? this.nonprofit?.cause?.causeID : 0;
                return this.nonprofitService.getSimilarNonprofits(causeID);
              })
            );
          })
        );
      })
    ).subscribe((response) => {
      this.similarNonprofits = response;
    });

I would like to know if the above is the correct way to chain concatMaps in Angular RxJS. The other two calls rely on the "nonprofit" in question being retrieved so that its object can be returned. Rating and Similar Nonprofits can be retrieved at the same time so I was thinking there would be some way I could do this without nesting those concatMaps within each other.


Solution

  • If you need to be using all the previous values it usualy ends with nesting more and more chains but in this case it seems already too complicated so you can map() each inner Observable into an array (or object) like the following:

    this.route.params.pipe(
      concatMap((param) => {
        const ein = param['nonprofit-id'];
        return this.nonprofitService.getNonprofit(ein).pipe(
          map(nonprofit => [ein, nonprofit]),
        );
      ),
      concatMap(([ein, nonprofit]) => {
        const ratingID = ...;
        this.nonprofitService.getRatingForNonprofit(ein, ratingID).pipe(
          map(nonprofitRating => [nonprofitRating, ein, nonprofit]),
        );
      }),
      concatMap(([nonprofitRating, ein, nonprofit]) => {
        const causeID = ...;
        return this.nonprofitService.getSimilarNonprofits(causeID).pipe(
          map(similar => [similar, nonprofitRating, ein, nonprofit]),
        );
      }
    ).subscribe(([similar, nonprofitRating, ein, nonprofit]) => { ... });
    

    Obviously, you don't have to unwrap each array passed as a parameter to consecutive concatMaps but I hope you get the point.