RXJS switchMap

In this tutorial we shall see what is a switchMap and how to use it.

What is switchMap?

The SwitchMap operator of rxjs is used to switch between emission. It switches from one observable to the other observable by cancelling the previous observable and switches to the new observable.

Create a new angular project

Lets create an angular application using the angular cli command.

ng new switchmap-tutorial

Create HttpService to handle api calls

Lets create a service named HttpService to make http api call. Enter the following angular cli command to create a service.

ng g s services/http

Now open the file and modify the code as below.

import { Injectable } from '@angular/core';
import { HttpClient} from '@angular/common/http';
import { Observable} from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class HttpService {

  constructor(private http: HttpClient) {
  }

  getCall(url: string): Observable<any> {
    return this.http.get(url);
  }
}

Create a service RxjsService to add switchMap

Now create a service using the below angular cli command.

ng g s services/rxjs

This will create us a service in the services folder. Now open the rxjs.service.ts file and add the following code.

import { Injectable } from '@angular/core';
import { from } from 'rxjs';
import { switchMap} from 'rxjs/operators';
import { HttpService } from '../services/http.service';
@Injectable({
  providedIn: 'root'
})
export class RxjsService {

  domainUrl = 'https://reqres.in/api/users?page=';
  reqArray = [1, 2, 3, 4, 5];
  constructor(private httpService: HttpService) { }

  switchMapCall() {
    from(this.reqArray).pipe(
      switchMap(id => this.httpService.getCall(this.domainUrl + id))
    ).subscribe((value) => {
      console.log(value);
    });
  }
}

The domainUrl contains the api url.

The reqArray is an array of integers to make api call by appending to the above domainUrl.

The switchMapCall() function, contains the from rxjs operator, which is used to convert an array to an observable.

Here, the from operator takes reqArray array variable as parameter and emit values of array one by one.

Next, we pipe the obervable and pass the array value switchMap operator one by one.

The switchMap operator gets the integers in the array one by one in the id parameter and then it appends the id to the domainUrl and form a url and makes an api call.

But before the api call returns, the result the next integer will be piped and passed to the switchMap, which now cancels the previous api call and forms new url with 2 as id value and makes api. In the meantime, the value 3 is passed to the id parameter and the previous api call will be cancelled. Similar thing will happen continously and only the final api call with id value of 5 will complete the api call and return the result.

The returned result is subscribed using subscribe function and print the result to the console.

Add RxjsService to the AppComponent

Open the app.component.ts file and modify the code as below.

import { Component, OnInit } from '@angular/core';
import { RxjsService } from './services/rxjs.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {

  constructor(private rxjsService: RxjsService) {
  }
 
  ngOnInit(): void {
    this.rxjsService.switchMapCall();
  }
}

Now run your application and press the F12 key to open the debugger option and select the Network tab and check out.

You will notice only the final api call will be successful and the rest of the calls gets cancelled.

What if suppose you want to call an api and use its result to make another api.

Some of them will come up with the solution of subscribing inside another subscribe function. Thats not a good practise to work with. Lets see how to use switchMap to solve the problem.

Add syncSwitchMapCall function to make call one after the other using switchMap

Open the rxjs.service.ts file and add modify the code as below.

import { Injectable } from '@angular/core';
import { from, throwError } from 'rxjs';
import { switchMap, catchError } from 'rxjs/operators';
import { HttpService } from '../services/http.service';
@Injectable({
  providedIn: 'root'
})
export class RxjsService {

  domainUrl = 'https://reqres.in/api/users?page=';
  reqArray = [1, 2, 3, 4, 5];
  constructor(private httpService: HttpService) { }

  switchMapCall() {
    from(this.reqArray).pipe(
      switchMap(id => this.httpService.getCall(this.domainUrl + id))
    ).subscribe((value) => {
      console.log(value);
    });

  }

  syncSwitchMapCall() {
    this.httpService.getCall(this.domainUrl + '1').pipe(
      switchMap((result1) => {
        console.log(result1);
        // Can process something with the result obtained in result1.
        return this.httpService.getCall(this.domainUrl + '2');
      }),
      switchMap((result2) => {
        console.log(result2);
        // Can process something with the result obtained in result2.
        return this.httpService.getCall(this.domainUrl + '3');
      }),
      catchError((error) => {
        return throwError(error);
      })
    ).subscribe((result3) => {
      // Finally, result will be returned only for 3rd api call.
      console.log(result3);
    }, (error) => {
      console.log(`Error occured`, error);
    });
  }
}

Here, we have created a function syncSwitchMapCall().
First, it makes api call to an url using getCall() function of HttpService and pipe the response and gives it to a switchMap operator. This operator will get the result and logs it to the console and makes the second call and returns the observable to the second switchMap operator.

Now it holds the result of the second api call. If we need to get the value from it we can get it from result2 variable. Now the second switchMap calls the third api call and returns an observable.

This observable will be subscribed and the final result will be logged to the console.

If any error occurs, it will be catched by the catchError and it throws the error. The error will be caught by the second callback function of subscribe function.

Open the app.component.ts file and instead of calling switchMapCall function call the syncSwitchMapCall function.

import { Component, OnInit } from '@angular/core';
import { RxjsService } from './services/rxjs.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {

  constructor(private rxjsService: RxjsService) {
  }
 
  ngOnInit(): void {
    this.rxjsService.syncSwitchMapCall();
  }
}

Run your application and press F12 and check the Console and Network tab. It looks as below.


Most Read