Angular
Go Reactive With Angular Async Pipe
Subscribe to an Observable
or Promise
in the template and get the latest value it has emitted

We can use Angular async pipe to access an Observable or a promise from the template.
The angular documentation describes the async pipe very well: “The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted.”.
I will just expand a bit here:
- The async pipe subscribes to an Observable or Promise when the component is initialized.
- It returns each value emitted by the Promise or Observable.
- When a new value is emitted, the async pipe marks the component to be checked for changes. It runs change detection to update the UI accordingly.
- When the component gets destroyed, the async pipe unsubscribes automatically to avoid potential memory leaks.
The last point is especially exciting because we don’t need to unsubscribe manually!
Angular async pipe in practice
Let’s have a look at the following angular application.
Class component
The class component declares the numbers variable. The variable is of type array of numbers and it is initialized to [1, 3, 5, 7, 9]
.
import { Component } from '@angular/core';...
export class AppComponent{
numbers: number[] = [1, 3, 5, 7, 9];
}
The template uses numbers to display a paragraph for each element in the numbers array. Each paragraph displays an item from the array.
At this point, we are using *ngIf="numbers"
in the template. This is redundant but it will come useful later. Furthermore, it is a straightforward way to handle conditional situations.
<div *ngIf="numbers"> <p *ngFor="let n of numbers">{{ n }}</p></div>
Now, we will make this code reactive.
First, we import OnInit to initialize the new observable when the component is initialized.
import { Component, OnInit } from '@angular/core';
...
export class AppComponent implements OnInit{
numbers: number[] = [1, 3, 5, 7, 9];
ngOnInit() {}
}
Second, we change the name of the variable numbers to be numbers$
of type Observable<number[]>
. The dollar sign $
is a convention to indicate that the variable is an Observable.
Finally, we assign the Observable created by of
to the Observable property numbers$
. Briefly speaking, the built-in function of
converts the arguments to an observable sequence.
Here is the code in app.component.ts:
Template
We move to the template to use the Angular async pipe and get the values returned by the numbers$
Observable.
- First, we check if the
numbers$
Observable is defined with*ngIf=”numbers$”
, - then, we pipe the
numbers$
Observable through the async pipe e.g.”numbers$ | async”
, to access its emitted values. As we said above, the angular async pipe automatically subscribes to the Observable and handles unsubscribe. - By using
as numbers
we assign the emitted value to a variable that we can use in the template. In our case, numbers will be an array of numbers. - Finally, we use the numbers variable in ngFor and we iterate through the item in the array to generate a new paragraph for each item.
<div *ngIf="numbers$ | async as numbers"> <p *ngFor="let n of numbers">{{ n }}</p></div>
Benefits of using Angular async pipe
Here are some of the main benefits that you get while using the async pipe:
- no need to subscribe
- no need to unsubscribe
- better change detection
Change detection refers to the ability to update the UI when the underlying data changes. Thanks to change detection the UI will always show the most updated data from the component.
The most common change-detection strategies are
- Default. It uses the default
checkAlways
strategy. Checks every component when any change is detected - On push. It checks the component for changes only when
@Input
properties changes, Events emit, or Observables emit. In so doing, the on-push strategy minimizes change detection cycles by using the CheckOnce strategy.
By binding an Observable in the template we follow the on-push strategy. To enable this change detection strategy, we need to set it in the component decorator as follows:
@Component({
templateUrl: './app.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
Error Handling with catchError
If we get an error, the Observable stream stops and does not emit any more items. Therefore, it is important to catch and handle errors properly.
The RxJS catchError
operator is an error-handling operator:
- It subscribes to an input stream.
- If an error occurs,
catchError
unsubscribes from the input stream and returns a replacement observable. If no error occurs, the input stream emits items to the output stream. - Then, it creates an output stream depending on the occurrence of errors. It might optionally rethrow an error.
As reported in the documentation, catchError
“Catches errors on the observable to be handled by returning a new observable or throwing an error. […] Handles errors from the source observable, and maps them to a new observable.“.
Therefore, we can extrapolate two basic error-handling strategies:
- catch & replace
- catch & rethrow
Both strategies use the catchError
operator.
Catch & Replace
Using the catch & replace strategy, we catch an error and replace it with something that is more suitable to continue:
- an Observable that emits some alternative data
- an Observable that emits an empty value
- the EMPTY rxjs constant. The
EMPTY
constant defines an observable that emits no items and completes.
Using the catch and replace strategy, catchError
replaces the error Observable with a new Observable.
// Catch & Replace StrategycatchError((err) => { this.errorMessage = err;
return EMPTY;})
The marble diagram in the rxjs documentation explains this strategy well.
The arrows represent Observables and the marbles represent emitted values.
In the following catchError
marble diagram, we see that an Observable emits the values a
and b
before encountering an error represented by the X symbol.
Using a catch & replace strategy, catchError
catches the error and emits the values 1, 2, 3, and complete, represented by the | symbol.
Thanks to this approach, the final outcome will seem like a single Observable stream that emits a, b, 1, 2, 3, and complete.
Catch & Rethrow
The catch & rethrow strategy returns a replacement Observable by using the rxjs throwError creation operator.
The throwError operator “creates an observable that will create an error instance and push it to the consumer as an error immediately upon subscription“. This operator emits no items.
The throwError operator is a creation operator:
- It creates and returns a replacement Observable that emits no items. Technically, it returns
Observable<never>
- It emits an error notification and stops the newly created Observable.
This strategy is generally used for error propagation.
// Catch & Rethrow Strategy
catchError((err) => {
return throwError(err);})
The documentation literally says “Just errors and does nothing else”.

Summary
- Use Angular async pipe to avoid using subscribe and unsubscribe manually. Furthermore, it is a good way to use an RxJS Declarative Pattern in Angular
- The Angular async pipe optimizes change detection
- Take care of error handling with
catchError
, either by using catch & replace or catch and rethrow