Tutorial

Managing Subscriptions in Angular With the Async Pipe

Published on May 3, 2017
author

Alligator.io

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

@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 our products

About the authors
Default avatar
Alligator.io

author

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.

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!

Become a contributor for community

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

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.