Reputation: 1433
I am successfully subscribing to an observable in a couple of different components in my Angular/Ionic app. However, because I am doing so manually, that also means I need to manually unsubscribe to them, which I currently do in my ngOnDestroy()
life cycle hook.
The component code implementation I have, that IS working, looks like this:
getPlayerStats() {
this.playerSubscription = this.mainService.getPlayerStats(this.username).subscribe(
user => {
this.user = user;
},
error => this.errorMsg = error
);
}
My view code for the component looks like this:
<ion-card *ngIf="user">
... display user info
</ion-card>
And the service method that is called here looks like this:
getPlayerStats(username: string) {
const req = `users/stats/${username}`;
return this.apiService.sendRequest(req);
}
What I'd like to do, but am having difficulty getting to work, is using the async
pipe do the subscribing in my HTML view. That'd be cleaner because then I wouldn't have to be so verbose and I wouldn't have to manually subscribe and unsubscribe in the components where I use this. My understanding is that this is also the recommended way of handling these scenarios, for precisely these reasons.
What would that code look like? I tried this but it did not work:
getPlayerStatus() {
this.user = this.mainService.getPlayerStats(this.username);
}
And in my HTML view I did this:
<ion-card *ngIf="user | async">
... display user info
</ion-card>
But as I say, this isn't working. What do I need to change here? How can I call the service getPlayerStats()
method, but handle the subscribing in the component view with the async pipe?
Upvotes: 1
Views: 2117
Reputation: 31125
You could try to use the *ngIf
directive's as
signature. It also allows you to use the notification multiple times with a single async
. Assuming that the observable is an HTTP call, remember that each async
pipe would trigger a new request since it's a cold observable.
Usual convention is to suffix an observable variable with a dollar sign. So following it, the controller would be
user$: any;
getPlayerStatus() {
this.user$ = this.mainService.getPlayerStats(this.username).pipe(
catchError(error => { // <-- HTTP error handling
this.errorMsg = error;
return of(error); // <-- return an observable from `catchError`
}
);
}
And the template using this variable would be
<ng-container *ngIf="(user$ | async) as user">
<ion-card>
... display user info
{{ user | json }}
{{ user.name }}
...
</ion-card>
</ng-container>
Also it goes without saying, but for this to work, the getPlayerStatus()
function should be called at least once to initialize the this.user$
variable.
Upvotes: 4