Tutorial

Managing Subscriptions in Angular With the Async Pipe

Published on May 3, 2017
Default avatar

By Alligator.io

Managing Subscriptions in Angular With the Async Pipe

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

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';

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

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

  ngOnDestroy() {
    this.timeSub.unsubscribe();
  }
}

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';

@Component({
  selector: 'app-root',
  template: `Time: {{ time$ | async | date:'mediumTime' }}`
})
export class AppComponent {
  time$ = Observable
    .interval(1000)
    .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.component.html
<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
    .of([
      {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′'},
    ])
    .delay(1000);
}

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

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

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 }}
</span>

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

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.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Alligator.io

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel