Reputation: 327
I've created my own db.json
server using typicode/json-server that looks like this -
{
"cart": [
{
"cartId": 1,
"products": [
{ "pId": 1, "name": "aaa", "quantity":.. },
{ "pId": 2, "name": "bbb", "quantity":.. }
]
},
{
"cartId": 2,
"products": [{ "pId": 2, "name": "bbb", "quantity":.. }]
}
]
}
This is the method to add a product to a cart:
addProductToCart((productObj:any)) {
this.getCart() // uses POST, reference '/cart', returns observable
.subscribe(cartId => {
this.getProducts(cartId, productObj.pId) // uses GET, reference '/cart/cartId/pId', returns observable
.subscribe(product => {
// update properties of product here..
});
});
}
I'm new to Angular and I understand that nested observables are not best-practice.
How can I avoid using nested observables?
Is there a way to write the same method using a different approach?
Upvotes: 0
Views: 261
Reputation: 556
I would advise looking into the mapping operators provided by RxJS.
There are 3 types (that i know of): switchMap
, concatMap
, mergeMap
Each of maps an observable emission to another observable which is then subscribed to and propagated to the outer subscription handler.
You may ask now, if they all do the same, why are there 3 different names for it? Well, all of them do it a little differently. ;)
First - switchMap
: observables are streams, so for each new emission switchMap
, turns it into another (inner) observable, but when the outer observable emits a new value, earlier inner subscriptions are cancelled, therefore only 1 inner subscription at a time is possible.
mergeMap
: like the name implies, it "merges" all inner observables into the stream and emits them without any special order.
concatMap
: almost like mergeMap
but it respects order, so items emitted by the outer stream, also get emitted in the same order from the inner observable.
When to use what?
For order-dependent streams you obviously want to use concatMap
, if you value throughput more than order go for mergeMap
. switchMap
is best for searches and streams where you "don't care" about older values, be careful tho, since switchMap
cancels inner observables http calls might not get completed.
Of course there's a lot more stuff to discover in RxJs (e.g. resultSelector
s for the mapping operators). This is just intended as a brief overview.
Further reading:
https://medium.com/@luukgruijs/understanding-rxjs-map-mergemap-switchmap-and-concatmap-833fc1fb09ff
https://www.learnrxjs.io/operators/transformation/switchmap.html
https://www.learnrxjs.io/operators/transformation/mergemap.html
https://www.learnrxjs.io/operators/transformation/concatmap.html
RxJs docs. (they have nice marble diagrams)
Now for your example:
addProductToCart(productObj: any) {
this.getCart()
.pipe(
switchMap(cartId => this.getProducts(cartId, productObj.pId))
)
.subscribe(product => {
// update properties of product here..
});
}
I assume getCart()
only emits the cart once and we dont need to worry about cancelling the inner subscription. You could also use any other of these operators if the assumption holds.
Upvotes: 3