Angular RxJS tap

By Arvind Rai, November 19, 2018
This page will walk through Angular RxJS tap example. RxJS tap performs side effects for every value emitted by source Observable and returns an Observable identical to the source Observable until there is no error. tap is the pipeable operator and it is the changed name of the RxJS do operator. Angular 6 uses RxJS 6 that has been shipped with pipeable operators which can be used independent of an Observable. To avoid the conflict with JavaScript keyword, some RxJS operators name has been changed such as do changed to tap, catch changed to catchError, switch changed to switchAll and finally changed to finalize. These operators are imported from rxjs/operators. For example tap is imported as following.
import { tap } from 'rxjs/operators'; 
Pipeable operators such as tap, are used within pipe function of Observable. tap performs side effects only when the Observable returned by tap is subscribed. tap can be used to debug values emitted by Observable or to perform any side effect.

Technologies Used

Find the technologies being used in our example.
1. Angular 7.0.0
2. Angular CLI 7.0.3
3. TypeScript 3.1.1
4. Node.js 10.3.0
5. NPM 6.1.0
6. RxJS 6.3.3

tap

tap is a RxJS pipeable operator that returns identical Observable as source Observable and can be used to perform side effect such as logging each values emitted by source Observable. tap is declared as following.
public tap(nextOrObserver: Observer | function, error: function, complete: function): Observable 
tap has three optional parameters.
nextOrObserver: A normal Observable object to perform side effect.
error: Callback for errors in source Observable.
complete: Callback for completion of the source.

Find the sample example.
of(1, 2, 3, 4).pipe(
 tap(el => console.log("Process "+ el),
	err => console.error(err),
	() => console.log("Complete")
 ),
 filter(n => n % 2 === 0)
).subscribe(el => console.log("Even number: "+ el)); 
We will get following output.
Process 1
Process 2
Even number: 2
Process 3
Process 4
Even number: 4
Complete 
In the above example we can see that first callback of tap is logging each value emitted from source Observable. Second callback is to log error but there is no error in source Observable hence error is not logged. Third callback is logging the message of completion that all values have been emitted from source Observable.

As the parameters of the tap is optional, we can also use tap as following.
of(1, 2, 3, 4).pipe(
  tap(el => console.log("Process "+ el)),
  filter(n => n % 2 === 0)
).subscribe(el => console.log("Even number: "+ el)); 
We can also use tap multiple times to debug values at different stages. Find the sample code snippet.
of(1, 2, 3, 4).pipe(
  tap(el => console.log(el)),
  filter(n => n % 2 === 0),
  tap(el => console.log(el)),
  map(n => n + 10),
  tap(el => console.log(el)),
  scan((sum, n) => sum + n),
  tap(el => console.log(el))
).subscribe(result => console.log("Result: "+ result)); 

Complete Example

tap-demo.component.ts
import { Component, OnInit } from '@angular/core';
import { Observable, of } from 'rxjs';
import { tap, map, filter, retry, catchError } from 'rxjs/operators';
import { TapDemoService } from './tap-demo.service';

@Component({
   selector: 'app-tap-demo',
   templateUrl: './tap-demo.component.html'
})
export class TapDemoComponent implements OnInit { 
   stdNames$: Observable<string[]>; 
   countryName$: Observable<string>;
   countryStates: string[];

   constructor(private mapDemoService: TapDemoService) { }
   
   ngOnInit() {
     this.getStdNames();
     this.getCountryName();
     this.getCountryStates();
      
     of(1, 2, 3, 4).pipe(
        tap(el => console.log("Process "+ el),
            err => console.error(err),
            () => console.log("Complete")
        ),
        filter(n => n % 2 === 0)
     ).subscribe(el => console.log("Even number: "+ el));

     let cities = ["Varanasi", "Mathura", "Ayodhya"];
      of(cities).pipe(
        tap(c => console.log(c.length)),
        map(dataArray => dataArray.join(", "))
     ).subscribe(res => console.log(res)); 

   }

   getStdNames() {
    this.stdNames$ = this.mapDemoService.getStdNames().pipe(
      tap(std => console.log(std)),
      map(res => res.split(","))
    );
   }	

   getCountryName() {
    this.countryName$ = this.mapDemoService.getCountry().pipe(
      tap(cname => console.log("Accessing country name...")),
      map(country => country.getCountryName()),
      tap(cname => console.log(cname)),
      catchError(err => {
        console.error(err);
        return of("");
      })
    );
   }

   getCountryStates() {
    this.mapDemoService.getCountry().pipe(
      retry(2),
      tap(cname => console.log("Accessing country states...")),
      map(country => country.getCountryStates()),
      tap(states => console.log(states)),
      catchError(err => {
        console.error(err);
        return of([]);
      })
    )
    .subscribe(res => this.countryStates = res); 
   }
} 
tap-demo.component.html
<b>Student Names</b>
<ul>
  <li *ngFor="let name of stdNames$ | async" >
    {{name}}
  </li>
</ul>

<b>Country Name</b>
<div *ngIf="countryName$ | async as myCountryName">
  {{myCountryName}} 
</div>

<b>Country States</b>
<ul>
  <li *ngFor="let state of countryStates" >
    {{state}}
  </li>
</ul> 
tap-demo.service.ts
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { MyCountry } from './my-country';

@Injectable({
    providedIn: 'root'
})
export class TapDemoService {
    getStdNames(): Observable<string> {
      return of("Mahesh, Krishna, Ram");
    }	
    getCountry(): Observable<MyCountry> {
      return of(new MyCountry());
    }
} 
my-country.ts
export class MyCountry {
   getCountryName() {
       return "India";
   }  
   getCountryStates() {
       return ["UP", "MP", "Assam", "Kerla"];
   }
} 
app.component.ts
import { Component } from '@angular/core';

@Component({
   selector: 'app-root',
   template: `
		<app-tap-demo></app-tap-demo>
    `
})
export class AppComponent { 
} 
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent }  from './app.component';
import { TapDemoComponent }  from './tap-demo.component';
import { TapDemoService } from './tap-demo.service';

@NgModule({
  imports: [     
      BrowserModule,
      HttpClientModule,
      FormsModule,
  ],
  declarations: [
      AppComponent,
      TapDemoComponent
  ],
  providers: [
  ],
  bootstrap: [
      AppComponent
  ]
})
export class AppModule { } 

Run Application

To run the application, find the steps.
1. Download source code using download link given below on this page.
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
3. Run ng serve using command prompt.
4. Access the URL http://localhost:4200
Find the print screen of the output.
Angular RxJS tap

References

RxJS tap
Angular: The RxJS library
Pipeable Operators

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI









©2023 concretepage.com | Privacy Policy | Contact Us