Managing Subscriptions in Angular With the Async Pipe

The built-in async pipe in Angular 2+ gives us a great tool to easily manage observable subscriptions. With it, we can learn to avoid having to manually subscribe to observables in component classes for most cases.

Let’s say we want to have an observable that gives us the current time every second. Without using the async pipe, we might do something like this:

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/map';

  selector: 'app-root',
  template: `Time: {{ time | date:'mediumTime' }}`
export class AppComponent implements OnInit, OnDestroy {
  time: Date;
  timeSub: Subscription;

  ngOnInit() {
    this.timeSub = Observable
      .map(val => new Date())
      .subscribe(val => this.time = val);

  ngOnDestroy() {

In our OnInit hook we created an observable that emits a value every second and maps that value to a new date. We then subscribed to that observable and set our time class variable to the emitted value. We also made sure to unsubscribe from the observable when the component is destroyed to clean up after ourselves.

In the template, we used the built-in date pipe to transform the date into our desired format of minutes and seconds.

It’s quite a bit of boilerplate code however, and if we forget to unsubscribe we run the risk of creating memory leaks. We can greatly simplify, and here’s the same functionality implemented using the async pipe instead:

import { Component } from '@angular/core';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/map';

  selector: 'app-root',
  template: `Time: {{ time$ | async | date:'mediumTime' }}`
export class AppComponent {
  time$ = Observable
    .map(val => new Date());

The async pipe takes care of subscribing and unwrapping the data as well as unsubscribing when the component is destroyed.

We can also use the async pipe to unwrap and pass data to an input for a child component:


<app-child [time]="time$ | async"></app-child>

And the child now has noting to do really but to display the data.

Async Pipe with ngFor

Let’s say we have a slightly more complex data structure available as an observable and we set an artificial delay of 1 second before getting its value (mimicking a network request):

import { Component } from '@angular/core';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/delay';

@Component({ ... })
export class AppComponent {
  cities$ = Observable
      {name: 'Los Angeles', population: '3.9 million', elevation: '233′'},
      {name: 'New York', population: '8,4 million', elevation: '33′'},
      {name: 'Chicago', population: '2.7 million', elevation: '594′'},

In the template we can unwrap and subscribe to the data when it arrives with an ngFor directive like this:

  <li *ngFor="let city of cities$ | async">
      Name: {{ }},
      Population: {{ city.population }},
      Elevation: {{ city.elevation }}</li>

Async Pipe with ngIf

Here’s an example making use of the ngIf structural directive. Our observable looks like this:

word$ = Observable.of('Abibliophobia');

And our template looks like this:

<span *ngIf="(word$ | async)?.length > 9; else shortWord">
  Long word: {{ word$.value }}

<ng-template #shortWord>
  Short word: {{ word$.value }}

And we’ll get:

Long word: Abibliophobia

Notice how we pipe the word$ observable through async, but wrap it in parentheses to then be able to check the length on the unwrapped value. We also make use of the Elvis operator (?) to avoid an error when the value of word$ is not yet available.

✖ Clear

🕵 Search Results

🔎 Searching...