Yesterday, we wrote about how to use the async
pipe to automatically subscribe and unsubscribe from our observables.
When I teach that topic, people usually have at least one of these two objections:
What if I also need the data from that subscription in my Typescript code?
At first, using the async
pipe seems only to give you access to the data in your HTML templates. That isn’t the case, though, because you can still use the tap operator to “spy” on your observable and get the data from there. For instance (complete example here):
this.name$ = nameService.getName().pipe(
tap(name => this.name = name)
);
Code language: TypeScript (typescript)
And then in the HTML template:
<p>Name from async pipe: {{ name$ | async }}</p>
Code language: HTML, XML (xml)
What if I need to read multiple properties from the object in that subscription?
Another way to put it is that you don’t want to end up doing something like this:
<p>First name: {{ (user$ | async)?.firstName }}</p>
<p>Last name: {{ (user$ | async)?.lastName }}</p>
Code language: HTML, XML (xml)
The above code is pretty hard to read and requires one subscription for each property. This alone can be a disaster, as each subscription might trigger an HTTP request for the same data from the server!
Instead, you can do something like this, which uses only one subscription, stores the result in a local variable, then renders the data when it’s available. This technique works with any structural directive, such as *ngIf
or *ngFor
:
<div *ngIf="user$ | async as user">
<p>First name: {{ user.firstName }}</p>
<p>Last name: {{ user.lastName }}</p>
</div>
Code language: HTML, XML (xml)
If changing the DOM structure by adding an element to accommodate that subscription bothers you, then you can use ng-template
instead, though the syntax here can be a little bit unsettling, too:
<ng-template [ngIf]="user$ | async" let-user>
<p>First name: {{ user.firstName }}</p>
<p>Last name: {{ user.lastName }}</p>
</ng-template>
Code language: HTML, XML (xml)
Ok, that’s probably plenty enough for today. Tomorrow, we’ll see how we can do even better than this.