How to use Async pipe in Angular

Posted By : Damini Sharma | 24-Aug-2019

What is the angular async pipe?


The angular async pipe permits the subscription to observables within the angular template syntax. It also takes care of unsubscribing from observables automatically.

Let's take a look at a count incrementing component's example:
 

import { Component } from '@angular/core'
import { Observable } from 'rxjs'

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  observable: Observable<number>

  ngOnInit() {
    this.observable = Observable.create(observer => {
      let value = 0
      const interval = setInterval(() => {
        observer.next(value)
        value++
      }, 1000)

      return () => clearInterval(interval)
    })
  }
}


To display that value we can reference the observable property and use the async pipe to resolve the observable to the current value:

<p>{{ observable | async }}</p>

A common use case is displaying values received from a REST-Endpoint, as the angular HttpClient returns an observable.
 

Why should you use the async pipe?


There are many ways to subscribe to observables. The default way, certainly without angular, is to subscribe to the observable manually and update a separate property with the value:
 

import { Component } from '@angular/core'
import { Observable } from 'rxjs'

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  observable: Observable<number>
  latestValue: number;

  ngOnInit() {
    this.observable = Observable.create(observer => {
      ...
    });

    this.observable.subscribe(value => this.latestValue = value);
  }
}

we can then bind to that property without using the async pipe at all:

<p>{{ latestValue }}</p>

So why to use the async pipe then?

It turns out the code above is not all we need to do!

Because we subscribed to the observable manually, we also need to manually unsubscribe. Otherwise, we risk a memory leak when the component is destroyed.

To fix this, we need to unsubscribe when the component is destroyed. The best place to do that is the ngOnDestroy lifecycle hook:

import { Component } from '@angular/core'
import { Observable, Subscription } from 'rxjs'

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  observable: Observable<number>
  latestValue: number
  subscription: Subscription

  ngOnInit() {
    this.observable = Observable.create(observer => {
        ...
    })

    // To be able to unsubscribe later make sure to save a reference to subscription 
    this.subscription = this.observable.subscribe(
      value => (this.latestValue = value)
    )
  }

  ngOnDestroy() {
    // Unsubscribe when the component is destroyed
    this.subscription.unsubscribe()
  }
}

A cleaner and more reactive way of doing the same thing is to use the rxjs takeUntil operator with another observable/subject that we complete when the component is destroyed. In this case, the takeUntil operator is taking care of unsubscribing.

import { Component } from '@angular/core';
import {Observable,Subject, Subscription} from 'rxjs';
import {takeUntil} from 'rxjs/operators';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  observable$: Observable<number>;
  unsubscribe$: Subject<void> = new Subject<void>();
  latestValue: number;

  ngOnInit(){
    this.observable$ = Observable.create((observer) => {
        ...
    })

    this.observable$
          .pipe(takeUntil(this.unsubscribe$))
          .subscribe(value => this.latestValue = value);
  }

  ngOnDestroy(){
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }
}
This approach is especially useful when dealing with multiple observables per subscription, as we do not need to keep a list with all subscriptions.

when using the angular async pipe, all this additional syntax is not necessary, as the pipe itself takes care of unsubscribing from the observable once the component is destroyed. So, the async pipe makes our code cleaner.

Also, the methods showed above do not work with the onPush change detection strategy, which is used to do performance optimizations of components. Async pipe, works just fine with that.

That is why we should definitely use the async pipe whenever possible.
 

How to use the async pipe with *ngIf


The Interpolation is not the only data binding the async pipe can be used with.

You can also use it with the *ngIf directive:

<p *ngIf="(observable$ | async) > 5">{{ observable$ | async }}</p>

Note, that the braces are absolutely necessary in this case.
 

How to use the async pipe with *ngFor


In the same way we can use the async pipe with the ngIf directive, we can use it with the ngFor directive.

To do that, the observable has to resolve to an array type, not just a single value.

items$: Observable<number[]>;

We then use it in combination with the *ngFor directive like so:

<p *ngFor="let item of items | async">{{ item }}</p>

Conclusion

In this tutorial, we learned how we can use the angular async pipe to prevent memory leaks.


 

About Author

Author Image
Damini Sharma

Damini is a young enthusiastic web designer who loves to explore latest, cutting edge tools and technologies in web development.

Request for Proposal

Name is required

Comment is required

Sending message..