Angular RxJS tap

By Arvind Rai, January 25, 2024
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.

1. 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)); 

2. 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"];
   }
} 
Find the print-screen of the output.
Angular RxJS tap

3. Reference

RxJS tap

4. Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us