0

I'm receiving a list of cart items from a service subscription and I want to take each CartItem object in that list and use one of its fields as a parameter for another service call ... which returns its own list, a list of products. Here's the code representation:

  cartItems: CartItem[];
  products: Product[];
    
  fetchCartItems() {
    this.cartService.getCartItemsList().subscribe(
      cartItems => {
        this.cartItems = cartItems

        for (let cartItem of this.cartItems) {
          // find the product with the cartItem's product_id
          this.productService.getProduct(cartItem.product.id).subscribe(
            product => { this.products.push(product); }
          );
        }
      }
    );
  }

Is there a better way of doing this?

Louis M.
  • 5
  • 2
  • It's not in need of simplifying, it *doesn't work*. The list is empty when you start iterating over it, because subscriptions are asynchronous (that's why it takes a callback). Read about `.pipe`. – jonrsharpe Dec 13 '20 at 23:47
  • Does this answer your question? [How do I return the response from an Observable/http/async call in angular?](https://stackoverflow.com/questions/43055706/how-do-i-return-the-response-from-an-observable-http-async-call-in-angular) – R. Richards Dec 13 '20 at 23:49
  • I changed how I wrote the code on this question to reflect what I actually have, sorry. I'm informed enough to know about the asynchronous bit, but not enough to know if how I have it written can be written better using mechanism like pipe(). – Louis M. Dec 13 '20 at 23:59

2 Answers2

1

Subscription should never be nested instead you should use a flattening operator. I have created a sample implementation CodeSandbox

subs: Subscription;

  constructor(private http: HttpClient) {}

  ngOnInit() {
    this.subs = this.http
      .get("https://dog.ceo/api/breeds/list/all")
      .pipe(
        switchMap(({ message }) => {
          console.log(message);
          return this.http.get("https://dog.ceo/api/breeds/image/random");
        })
      )
      .subscribe(console.log);
  }

  ngOnDestroy() {
    this.subs.unsubscribe();
  }
Lambo14
  • 231
  • 1
  • 6
0

This is probably the most 1-1 translation of the code you've written without nesting subscriptions.

That being said, you can likely exchange the mergeMap for a switchMap, and perhaps even change merge(...array) for forkJoin(array) depending on your desired behaviour(s).

fetchCartItems() {
  this.cartService.getCartItemsList().pipe(
    mergeMap(cartItems  => merge(
      ...cartItems.map(cartItem => 
        this.productService.getProduct(cartItem.product.id)
      )
    ))
  ).subscribe(product => {
    this.products.push(product);
    console.log(product);
  });
}
Mrk Sef
  • 7,557
  • 1
  • 9
  • 21