SwitchMap is an RxJs operator which allows us to trigger some emission whenever another observable emit a value.
How does the switchMap operator work?
SwitchMap operator like all other RxJx operators starts by observing some outer source observable. then we are able to power the switchMap operator, add a result or inner observable in that operating. whenever our source is observable or outer observable, switchMap cancels the current stream and starts a new event stream. and then any other pipe operator below the switchMap just be dealing with the result of switchMap observable.
SwitchMap Interval example
In component.html file
<button #counterBtn type="button">Click here</button> <h1>Counter: {{ counter }}</h1>
In component.ts file
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { fromEvent, interval } from 'rxjs'; import { switchMap } from 'rxjs/operators'; @Component({ selector: 'app-switch-map', templateUrl: './switch-map.component.html', styleUrls: ['./switch-map.component.scss'] }) export class SwitchMapComponent implements OnInit { @ViewChild('counterBtn', { static: true, read: ElementRef }) counterBtnRef!: ElementRef; counter: number = 0; constructor() { } ngOnInit(): void { fromEvent(this.counterBtnRef.nativeElement, 'click') .pipe(switchMap((_event) => { console.log('new event', _event) return interval(1000) })) .subscribe(data => { console.log(data) this.counter = data; }) } }
So what are we doing here, let’s break down
We first define button and counter render HTML elements. and selected button element in component class via ViewChild
. I also define simple counter property in the component class.
Great, now breakdown observable stream
Via formEvent
, we are listening to the button click event inside the DOM
. and we are piping that with our switchMap
. So what will happen is whenever you will click on the button, It will going to reset your interval and the interval is also an observable which you are going to give elect counter within a certain interval. Interval! we are giving here is a second and we are subscribing that we are console log value and also assigning this value to our counter.
SwitchMap interval preview
SwitchMap search example with API request
In this example, I will implement an API search example with switchMap which solves multiple API request problems to save some memory and some bandwidth. This search example is completely used able for the real case and best use of switchMap in my opinion. let’s start …
How the search will work?
We will have a search option as search input. When the user will have typed some search terms and when search terms will be valid, That will hit the server then show the results. Great but some time and some queries take a little bit more time. In the meantime user typing again, Then the preview request will be canceled and In the meantime, new request will hit the server
Let’s start example
I am going to use angular reactive formControl for the search input field. So to use reactive formControl
. I need to import angular ReactiveFormsModule
and I will send HTTP request so I also need angular HttpClientModule
Import Modules
In the app.module.file, Add ReactiveFormsModule
and HttpClientModule
... import { HttpClientModule } from '@angular/common/http'; import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ ... imports: [ ... HttpClientModule, ReactiveFormsModule, ... ], ... }) export class AppModule { }
In component.html file
Define input field in the HTML component, which contains required formControl attribute value searchTerm (as FormControl) what will implement inside the component class.
<input [formControl]="searchTerm" type="text" autocomplete="false" placeholder="Search...">
In component.ts file
import { HttpClient } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; import { Observable } from 'rxjs'; import { debounceTime, distinctUntilChanged, filter, switchMap } from 'rxjs/operators'; @Component({ selector: 'app-switch-map', templateUrl: './switch-map.component.html', styleUrls: ['./switch-map.component.scss'] }) export class SwitchMapComponent implements OnInit { searchTerm: FormControl = new FormControl('', [Validators.required, Validators.minLength(3)]) constructor(private http: HttpClient) { } ngOnInit(): void { this.searchTerm.valueChanges .pipe( filter(() => this.searchTerm.valid), debounceTime(200), distinctUntilChanged(), switchMap((text) => { return this.fetchResult({ q: text }) }) ) .subscribe(data => { console.log('Subscribe data', data) }) } fetchResult(queryParams?: any): Observable<any> { const options = { ...(queryParams && { params: queryParams }) } return this.http.get('https://api.storerestapi.com/products', options) } }
Let’s explain …
searchTerm: searchTerm is a reactive form control. HttpClient: simply httpClient service injected for the API request. fetchResult: fetchResult method is for the server API requests. which return observable API response. the fetchResult method also takes the query parameter as the first argument.
Note: This is not a good way to have the API request method in the component class. Best use implement API request methods in the separate service files.
When users type terms, searchTerm tigger with method valueChanges
observable, which give input value. So now we can pipe this one with any observable RxJs operator.
- First we used filter rxjs operator for valid input field with required and required minimum 3 charactar.
- Next used operator is debounceTime operator. The debounceTime operator means when user stop type it’s will wait debounce time. It’s something like delay or setTimeout.
- Next used operator is distinctUntilChanged operator, which means if input value don’t change, it will not go next. example: If user type apple, and then the api will called. then user type apple food and suddent time user removed food, So it’s same was preview request. It should not be call another request. that’s why distinctUntilChanged used.
- After validating value, In here switchMap operator come. If input text validation the swichMap return new http request. Untill user stop typing. this valueChanges obervable rotating. So in this rotation if request is pending this request will cancel and new request will be call.
Next, we can subscribe to the search results.