Furkan Işıtan
Furkan Işıtan

Reputation: 84

set property of an observable object with an api call

I have a service function like the one below.


getByIdWithCategory(id: number): Observable<Product> {

    const category = new Category();
    category.name = 'sample category';

    return this.httpClient.get<Product>(this.baseUrl + `/${id}`)
      .pipe(map(product => ({...product, category})));
  }

I get the value returned from here with the async pipe in the template file. But I need to get the category from api. I need to subscribe for this. But then I can't unsubscribe. What is the best practice for this?

The function below does exactly what I want. But I couldn't find a way to unsubscribe from the api call I get the category from.

  getByIdWithCategory(id: number): Observable<Product> {

    return this.httpClient.get<Product>(this.baseUrl + `/${id}`)
      .pipe(
        tap(product => {
          this.categoryService.getById(product.id)
            .subscribe(category => {
              product.category = category;
            });
        })
      );
  }

Here's how in my product class.

export class Product {
  id: number;
  title: string;
  price: number;
  description: string;
  categoryId: number;
  image: string;

  category: Category;
}

Upvotes: 1

Views: 857

Answers (1)

Barremian
Barremian

Reputation: 31125

Try to avoid nested subscriptions. And subscribing inside the tap operator looks particularly inelegant. Instead you could use switchMap to map from one observable to another. And pipe map to the inner observable and return the whole object with the category property.

Try the following

getByIdWithCategory(id: number): Observable<Product> {
  return this.httpClient.get<Product>(this.baseUrl + `/${id}`).pipe(
    switchMap((product: Product) => {
      this.categoryService.getById(product.id).pipe(
        map((category: Category) => ({
          ...product,
          category: category
        }))
      )
    })
  );
}

Upvotes: 1

Related Questions