I have a beginner Angular project and I want to load a component where I get the ID of a record from the routerparams and from that I do an api call to my backend to get the data. The issue is that my return is Observable<Observable> and I'm not sure how to use this to get the data from the Product with that ID.
import { Component, Input, OnInit } from '@angular/core';
import { Product, ProductsService } from './products.service';
import { map, Observable } from 'rxjs';
import { ActivatedRoute } from '@angular/router';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-product-view',
standalone: true,
imports: [CommonModule],
template: `
product-view works!
<br />
<article class="product-panel" *ngIf="(product$ | async) as product">
{{product.id}}
//ABOVE CODE THROWS ERROR
//NOTE I WANT TO GET PRODUCT DATA BUT IT IS OBSERVABLE<Product>
</article>
`,
styles: ``
})
export class ProductViewComponent implements OnInit{
constructor(private productsService: ProductsService, private route: ActivatedRoute){}
product$: Observable<Observable<Product>>;
productId: string;
ngOnInit(): void {
this.product$ = this.route.paramMap.pipe(
map(params => {
return this.productsService.getProduct(params.get('id')!);
})
)
}
}
Here is my service:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
export interface Product {
id: string;
name: string;
category: string;
subCategory: string;
}
@Injectable({
providedIn: 'root'
})
export class ProductsService {
readonly URL = "http://localhost:5999/products";
constructor(private http: HttpClient) {
this.getProducts();
}
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>(this.URL);
}
getProduct(id:string): Observable<Product> {
return this.http.get<Product>(this.URL + "/" + id);
}
}
I could get the router param in the way shown below but I kind of like the way I set it up because if the id in the routeparams changes it will do another api call.
this.productId = this.route.snapshot.params['id'];
this.product$ = this.productsService.getProduct(this.productId);
(Note: for this method I would change the this.product$ to be of type Observable instead of Observable<Observable> )
Use switchMap (that transform an Observable in another observable) instead of map to return a simple Observable
//see that product$ is an Observable of Product
product$!:Observable<Product>
this.product$ = this.route.paramMap.pipe(
switchMap (params => {
return this.productsService.getProduct(params.get('id')!);
})
)