Subscriptions in Angular With the Async Pipe

Async Pipe

It unwraps a value from asynchronous types. It is subscribed to an observable or promise and will return the latest value which was emitted. It continuously checks for changes. Whenever a new value is emitted, the pipe supplies the component and its view with the latest value. The async pipe takes care of providing and subscribing to the data and unwraps the data when the component gets destroyed.

Examples

We have seen that we need to subscribe to the observable using subscribe() method and unsubscribe it after our job is done using the unsubscribe() method. To avoid any kind of memory leak, we need to unsubscribe to observables.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/observable/interval';
import { startWith, map } from 'rxjs/operators';
import { Observable } from 'rxjs';


@Component({
  selector: 'app-root',
  template: `Value: {{ x }}`
})
export class AppComponent implements OnInit, OnDestroy {
  x: any;
  timeSub: Subscription;

  ngOnInit() {
const myObservable = Observable.create((observer)=>{
      setInterval(()=>{
      observer.next(11);
    },1000)
 });

const mySubscription = myObservable.subscribe(obs=>{
   this.x = obs;
});

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

We have written the above code in which we subscribed to our observable and then unsubscribe it when our component gets destroyed to avoid any kind of memory leak. We will write the same code using the async pipe. Using async pipe we need not subscribe and unsubscribe. It automatically implements all that under the hook. This pipe checks for changes and updates the view with new emitted data.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/observable/interval';
import { startWith, map } from 'rxjs/operators';
import { Observable } from 'rxjs';


@Component({
  selector: 'app-root',
  template: `Value: {{ x$ | async }}`
})
export class AppComponent implements OnInit, OnDestroy {

  ngOnInit() {
 x$ = Observable.create((observer)=>{
      setInterval(()=>{
      observer.next(11);
    },1000)
 });

}

Async Pipe With *ngFor

Using ngFor we will have a complex object such as an array of objects with key and value pairs. The data is an observable which is coming from the API. We will see that we have a search box and a table in our component called a table component. Now we will go to table.component.html file and write the below code:

<div class="container-fluid ">
  <div class="row">
    <div class="col-md-12">
         <div class="owa-search-container">
            <input class="owa-form-input" id="search_networks" 
               name="search_networks" type='text' placeholder="Search..." 
               [formControl]="fcNetworks" />
       </div>
      <div class="row" *ngFor="let network of networks">
         {{ network.name}}
      </div>
    </div>
  </div>
</div>

Now we have to implement the search functionality in our table.component.ts file as follows:

import { Component, OnInit, ViewEncapsulation, NgZone } from '@angular/core';
import { FormControl } from '@angular/forms';
import { CustomerDetailsAuthGuard } from '../../../../../services/gaurds/customer-details.auth.guard';
import { ActivatedRoute } from '@angular/router';
import { NetworkService } from '../../../services/network.service';
import { AuthService } from '../../../../../services/auth/auth.service';
import { Observable } from 'rxjs';
import { startWith, map } from 'rxjs/operators';
import * as _ from "lodash";
import * as moment from 'moment';

@Component({
  selector: 'app-network-user-view',
  templateUrl: './network-user-view.component.html',
  styleUrls: ['./network-user-view.component.scss'],
  encapsulation: ViewEncapsulation.None,
})

export class TableComponent implements OnInit {
  fcNetworks = new FormControl();
  filteredNetworks: Observable<any[]>;
  networks: any[] = [];
  constructor(
    private _networkService: NetworkService,
  ) {

  ngOnInit() {
    this.loadNetworks();
    this.initSearchNetwork();
    this.fcNetworks.setValue("");
  }

  loadNetworks() {
    this._networkService.getNetworks().then((data) => {
      this.networks = data;
})
}
  initSearchNetwork() {
    this.filteredNetworks = this.fcNetworks.valueChanges
      .pipe(
        startWith(''),
        map(value => value ?
          ((value) => {
            const filterValue = value.toLowerCase();
            let res: any[] = this.networks.filter(
              item => item.networks.name.toLowerCase().indexOf(filterValue) > -1
            );
            return res;
          })(value)
          : this.networks.slice())
      );
  }
}
Now we have implemented our search function called initSearchNetwork() which will give us filteredNetworks which is observable when we type something in our search bar. Now we need to do apply async pipe in our HTML code as follows. Async pipe 

<div class="container-fluid ">
  <div class="row">
    <div class="col-md-12">
         <div class="owa-search-container">
            <input class="owa-form-input" id="search_networks" 
               name="search_networks" type='text' placeholder="Search..." 
               [formControl]="fcNetworks" />
       </div>
      <div class="row" *ngFor="let network of filteredNetworks|async"> // Changed networks to filteredNetworks with async pipe
         {{ network.name}}
      </div>
    </div>
  </div>
</div>

Comments