I am working my way through Moshs' Angular class building a simple shopping page. Since this tutorial is already quite old I had to work my way through the changes in bootstrap and angular and I did quite good until I got to the shopping cart section.
The issue I have here is, that I am using a mysql database instead of firebase and I my implementation to calculate the total number of items in my cart is not working as expected but I can not figure out why.
So what I am doing is the following: On my product page you can add / remove items to the cart - that data is sent to the server and after that I am returning the updated cart via a post request observable like this:
getCartContent(): Observable<ShoppingCart> {
return this.getOrCreateCart().pipe(
switchMap(cart => {
return this.http.post<ShoppingCart>(this.url 'cart_api.php', JSON.stringify(
[
'getCartContent',
{
cartId: cart
},
''
]
));
})
);
}
I use a switchmap here since I have to get the cartId first and then get the respective cart items. This is working fine, I get the cart data updated on the product page and writing the new cart data to the localstorage / console shows me that the data is returnded as expected.
What I now try to do is to show the total number of items in the cart in the navbar. Therefor I subscribed also in the navbar.ts to this observable and wanted to re-calculate the amount every time the getCartContent() is executed.
My code in the navbar looks like this:
ngOnInit() {
this.ShoppingCartService.getCartContent().subscribe(cart => {
console.log(cart); // just to see, if this subscription receives data
this.shoppingCartItemsCount = 0;
for (let productId in cart.ITEMS) {
this.shoppingCartItemsCount = Number(cart.ITEMS[productId]);
}
}
);
}
The result is, that the cart data is logged in the console correctly - but only once when I load the page - any change on the items in the cart are not reflected in the navbar subscription but working in the product page.
I am pretty sure I make a fallacy of thinking but I am totally stuck - any help is highly appreciated.
CodePudding user response:
I understand your confusion, actually, the getCartContent is called only once even though it returns an observable. What you need is a BehaviourSubject in your service class to reflect the changes. Below is a common practice how to implement it.
private cartContent$: BehaviourSubject<ShoppingCart> = new BehaviourSubject();
public listenToCartChanges(): Observable<ShoppingCart> {
return this.cartContent$.asObservable();
}
In order to push the changes to the subject you can add a tap on your function to push the changes to the BehaviourSubject.
getCartContent(): Observable<ShoppingCart> {
return this.getOrCreateCart().pipe(
switchMap(cart => {
return this.http.post<ShoppingCart>(this.url 'cart_api.php', JSON.stringify(
[
'getCartContent',
{
cartId: cart
},
''
]
));
}),
pipe(res => {
this.cartContent$.next(res)
}
);
}
Lastly, you need to subscribe to the function listenToCartChanges()
in your nav component (don't forget to unsubscribe on ngOnDestroy
to prevent memory leaks).