Reputation: 171
I'm doing a get request in order to retrieve the user role
private myOrders;
constructor(private userData: UserDataService) {
this.userData.getUser().subscribe((user: any) => {
//and then I'm doing a conditional get
if (user.role == "Admin") {
this.userData.getAdminOrders().subscribe((adminOrders: any) => {
this.myOrders = adminOrders
});
} else {
this.myOrders = user.orders
}
});
My app shows properly only the user.orders (the orders for the normal customers) but when I'm with the Admin account it only shows the first page load but then they disappear.
How can I manage those nested subscribtion? (They are http.get on my userDataService)
Upvotes: 5
Views: 12222
Reputation: 2397
Uses switchMap
operator and observable iif
and of
this.userData.getUser()
.pipe(
switchMap(({ role, orders }) =>
iif(
() => role === 'Admin',
this.userData.getAdminOrders(),
of(orders),
),
),
)
.subscribe(orders => (this.myOrders = orders));
never use a subscribe in another subscribe, because you create memory leacks, or for a cleaner and better solution, use async pipe as specified by @BizzyBob
Upvotes: 3
Reputation: 14740
You can avoid using nested subscriptions by using one of the "Higher Order Mapping Operators" LINK
This is just a fancy way of saying: operators that map the incoming value to another observable, subscribe to it, and emit those values. They also manage these "inner subscriptions" automatically.
The switchMap
will "switch" to a new observable whenever a new value is received. So, when you pass in the "user", map it to the appropriate observable based on the user.role
, it will subscribe to it and emit those values. When a new "user" value is received, it will unsubscribe from the previous observables, and subscribe to the new one.
Also, rather than subscribing in your component, you can define "myOrders" to be an Observable, which you can subscribe to in the template, like this:
public myOrders$ = this.userData.getUser().pipe(
switchMap(user => {
return user.role = 'Admin'
? this.userData.GetAdminOrders()
: of(user.orders));
}
);
Then, you can use the async
pipe in your template. This means you don't need to worry about managing subscriptions in your component.
<ul>
<li *ngFor="order of myOrders$ | async">{{ order.description }}</li>
</ul>
Upvotes: 3
Reputation: 1930
You should use one of the rxjs operators on this type of cases.
For this case I recommend you flatMap:
private myOrders;
constructor(private userData: UserDataService) {
this.userData.getUser().pipe(flatMap(user: any) => {
if (user.role == "Admin") {
return this.userData.getAdminOrders();
} else {
return of(user.orders)
}
}).suscribe((result) => {
this.myOrders = result
}
);
If user.role == "Admin"
is true, result
will be the result of the HTTP request in this.userData.getAdminOrders()
. On the other case, the result will be user.orders
.
Upvotes: 5