Home > Back-end >  Emit from Observable and then make additional REST API call for more detail
Emit from Observable and then make additional REST API call for more detail

Time:05-19

I have two methods which do HTTP calls to Rest APIs. One is getProducts() which will return a array of products and the other is getProductsDetail() which can take that array as parameter and will return the array of products with additional fields populated.

I would like to call these two APIs in sequence, with getProductsDetail() depending on the result of getProducts(), but i would like my Observable to emit the result from getProducts() as soon as that is ready. And then have getProductsDetail() emit with the extra detail when this call returns.

Is there a way to do this with an RxJS operator like concatMap or mergeMap? I would like to have my template start to display as soon as possible, but fill in the extra data when this is available

UPDATE:

Hi, thanks for the replies! I'm sorry I only pseudo code at the moment, but I think my initial attempt was going to be be something similar to what Authur had below

initProductsPage(): Observable<Products[]>{
this.productsService.getProducts().pipe(
  switchMap(
    (products: Products[]) => {
      // would like to also emit products here

      return this.productsService.getProductsDetail(products);
    }
  )

}

My understanding would be that in this case a subscriber to initProductsPage() would only recieve an output when getProductsDetail() returns. I'd like to have that subscriber get the products while getProductsDetails() is executing.

CodePudding user response:

Assuming both getProducts() and getProductsDetail() return an Observable<Product[]>, you could do something like this:

getProductsWithDetailsHydration(): Observable<Product[]> {
  const productsShared$ = this.getProducts().pipe(share()); // <- to share same GET products request.

  return merge(
    productsShared$, // <- 1st obs Gets and emits Products
    productsShared$.pipe( //<- 2nd obs Gets details using products response and emit Products with Details
      concatMap((products) => this.getProductsDetail(products))
    )
  );
}

Cheers

CodePudding user response:

Another approach would have been from API end is to have a getProductDetail$() method. Which can get details for a single product. Then you could easily use async in the template itself and fill the template.

Example Template Code

<ng-container *ngIf="getProduct$() | async as product">
    // Some info on product
    <div>{{product.title}}</div>
    <ng-container *ngIf="getProductDetail$(product.id) | async as productDetail">
         // Some info on product details
        <div>{{productDetail.description}}</div>
    </ng-container>
</ng-container>
  • Related