Real-life use cases for RxJS SwitchMap in Angular
The switchMap()
operator transforms an observable into another observable, while cancelling the previous subscription. By cancelling the previous subscription, the switchMap()
operator prevents memory leaks and ensures that only the latest observable is subscribed to.
Because of this, switchMap()
should be avoided in scenarios where every subscription needs to complete, for example when using the switchMap()
operator with database-written HTTP requests (POST, PUT, PATCH, DELETE). In this case mergeMap()
should be used instead.
In this article, we’ll discuss several real-life examples of how the RxJS switchMap()
operator can be used in Angular.
Some typical use cases for the switchMap()
operator are:
- Fetching Details from an API on a Routed Detail Screen
- Typeahead Search
Detail screen with switchMap()
@Component({
selector: 'my-car-brand-detail',
standalone: true,
imports: [CommonModule],
providers: [CarBrandService],
template: `
Details:
<ng-container *ngIf="carBrand$ | async as brand">
<p>Brand ID: </p>
<p>Brand Name: </p>
</ng-container>
`,
})
export class CarBrandDetailComponent {
private readonly carBrandService = inject(CarBrandService);
private readonly activatedRoute = inject(ActivatedRoute);
// Listen for changes on the Router Params and map the params to an ID value
private readonly id$ = this.activatedRoute.params.pipe(
map((params) => params['id'])
);
// Every time the id$ changes, the carBand will be fetched
public readonly carBrand$: Observable<CarBrand> = this.id$.pipe(
switchMap(
// SwitchMap returns an observable, in this case an Observable<CarBrand>
(id) => this.carBrandService.getById(id)
)
);
}
Check out the full example on Stackblitz.
Typeahead with switchMap()
and ReactiveForms
@Component({
selector: 'my-app',
standalone: true,
imports: [CommonModule, FormsModule, ReactiveFormsModule],
providers: [CarService],
template: `
<input [formControl]="searchTermControl" type="text">
<ul>
<li *ngFor="let brand of filteredCarBrands$ | async"></li>
</ul>
`,
})
export class AppComponent {
private readonly carBrandService = inject(CarService);
public readonly searchTermControl = new FormControl('');
public readonly filteredCarBrands$: Observable<string[]> =
// Every time the value changes of the fornControl this stream will be executed again
this.searchTermControl.valueChanges.pipe(
startWith(''), // Make observable hot => show all the car brands initially
debounceTime(300), // Wait 300ms before searching
switchMap((searchTerm) =>
// Returns a list of Car Brands
this.carBrandService.searchCarBrands(searchTerm)
)
);
}
Check out the full example on Stackblitz.
Typeahead search with switchMap()
and BehaviorSubject
@Component({
selector: 'my-app',
standalone: true,
imports: [CommonModule, FormsModule],
providers: [CarService],
template: `
<input [ngModel]="searchTerm$$.value" (ngModelChange)="searchTerm$$.next($event)" type="text">
<ul>
<li *ngFor="let brand of filteredCarBrands$ | async"></li>
</ul>
`,
})
export class AppComponent {
private readonly carBrandService = inject(CarService);
public readonly searchTerm$$ = new BehaviorSubject('');
private readonly searchTerm$ = this.searchTerm$$.asObservable();
// Every time the searchTerm is changed then the carBrandService.searchCarBrands function is called
public readonly filteredCarBrands$: Observable<string[]> =
this.searchTerm$.pipe(
debounceTime(300), // Wait 300ms before searching
switchMap((searchTerm) =>
// Returns a list of Car Brands
this.carBrandService.searchCarBrands(searchTerm)
)
);
}
Check out the full example on Stackblitz.
Conclusion
- The
switchMap()
operator is used to transform an observable into another observable. switchMap()
cancels the previous subscription.- Typically used for fetching data from an API on a routed detail screen or for a typeahead search.
Other articles you might like
-
Generating icon components from SVG files with NX and Angular
-
Angular + NGINX + Docker
-
How to Call the OpenAI API Directly from Angular (with streaming)
-
Custom TitleStrategy in Angular
-
RxJS catchError: error handling
-
RxJS distinctUntilChanged: filtering out duplicate emissions
-
RxJS combineLatest: how it works and how you can use it in Angular
-
Delaying streams with RxJS debounceTime
-
Transforming data with the RxJS Map operator
-
Typesafe view models with RxJS and Angular
-
Reactively storing and retrieving URL state in Angular
-
Let's build an Image Generator with OpenAI and Angular
-
Why you should externalize your Angular Configuration