I have a problem when rendering my "Product Edit Page" when I click a specific item in my list.
I have a method from a service that retrieves a specific data from firebase firestore.
product.service.ts
/**
* Get specific product
*/
getProduct(guid: string): Observable<IProduct> {
return new Observable((observer) => {
this.firebaseDb.collection('products')
.doc('XNRkodfbiRoKc2DYPA3o')
.onSnapshot((querySnapshot) => {
let product: IProduct;
product = <IProduct>querySnapshot.data();
product.guid = guid;
observer.next(product);
}, (error) => console.log(error.message));
});
}
The above method will be called in my Resolver as shown below.
product-resolver.service.ts
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<IProduct> {
const id = route.params['id'];
return this.productService.getProduct(id)
.pipe(
map(product => {
if (product) {
return product;
}
console.log(`Product was not found: ${id}`);
this.router.navigate(['/products']);
return null;
}),
catchError(error => {
console.log(`Retrieval error: ${error}`);
return of(null);
})
);
}
product-routing.module.ts
{
path: 'products/:id/edit',
component: ProductEditComponent,
canActivate: [AuthGuardService],
resolve: { product: ProductResolver }
}
The problem now is, whenever I click the edit button from my list, nothing happens. This supposed to be redirected to my edit product page and fill all the data from the textbox using this.route.snapshot.data['product']
.
I debug the route by passing enableTracing: true
to my routing and it seems it was stuck in Router Event: ResolveStart
. Can someone enlighten me why this is the behavior?
The router waits for the observable to complete. Ensure that it is completed after the first value is emitted by using take(1)
or first()
. E.g.:
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<IProduct> {
return this.productService.getProduct(route.paramMap.get('id')).pipe(
take(1),
map(product => {
if (!product) {
// noinspection JSIgnoredPromiseFromCall
this.router.navigate(['/404']);
return null;
} else {
return product;
}
})
);
}
P.S. you can cleanup your getProduct
method like this:
getProduct(guid: string): Observable<IProduct> {
return from(this.firebaseDb.collection('products').doc('XNRkodfbiRoKc2DYPA3o').onSnapshot()).pipe(
map((snapshot:any) => {
const product = <IProduct>snapshot.data();
product.guid = guid;
return product;
}),
);
}