LearnAI ToolsCareerPractice BuildsPlayDevelopmentContact
Lesson 2819 min read

Common RxJS Operators

Transform and combine Observable streams using the RxJS operators you'll reach for most often in Angular apps.

On this page 8 sections

Piping Operators

Operators transform an Observable into a new Observable, chained together using the .pipe() method — conceptually similar to chaining array methods like .map().filter(), but for a stream over time instead of a fixed collection.

import { map, filter } from 'rxjs/operators';
const evenDoubled$ = numbers$.pipe(
filter(n => n % 2 === 0),
map(n => n * 2),
);

map and filter

map transforms each emitted value; filter only lets through values matching a condition — the most fundamental, everyday operators.

getPosts() {
return this.http.get<Post[]>('/api/posts').pipe(
map(posts => posts.filter(p => p.published)),
);
}

switchMap

switchMap maps each emitted value to a new inner Observable (often another HTTP call), and automatically cancels the previous inner Observable if a new value arrives before it completes — essential for things like route-driven data fetching.

import { switchMap } from 'rxjs/operators';
this.route.params.pipe(
switchMap(params => this.postsService.getPost(params['id'])),
).subscribe(post => {
this.post = post;
});
Why "Switch"

If a user navigates from /posts/1 to /posts/2 before the first request finishes, switchMap cancels the now-irrelevant request for post 1 — preventing a slower, stale response from ever overwriting the correct, newer one.

debounceTime waits for a pause in emissions before letting one through — the standard pattern for a search box that shouldn't fire a request on every single keystroke.

import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
this.searchControl.valueChanges.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap(term => this.postsService.search(term)),
).subscribe(results => {
this.results = results;
});

combineLatest

combineLatest emits a combined array whenever any of the source Observables emits, once every source has emitted at least once — useful for combining several independent streams (like a filter and a page number) into one derived result.

import { combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
const filteredPosts$ = combineLatest([this.category$, this.searchTerm$]).pipe(
map(([category, term]) => this.filterPosts(category, term)),
);

Common Beginner Mistakes

Using mergeMap where switchMap is actually needed

mergeMap runs every inner Observable to completion without cancelling — for scenarios like route-param-driven fetches, this can let a stale, out-of-order response win; switchMap is usually the safer default.

Forgetting distinctUntilChanged alongside debounceTime

Without it, retyping the exact same search term (e.g. after backspacing and re-typing) can trigger a redundant request debounceTime alone won't filter out.

FAQs

Well over a hundred, but a small set — map, filter, switchMap, debounceTime, combineLatest, catchError, tap — covers the vast majority of everyday Angular code.

Order matters — each operator receives the output of the one before it in the pipe, so debounceTime before switchMap behaves differently than the reverse.

Summary

A handful of RxJS operators — map, filter, switchMap, debounceTime, combineLatest — cover most real-world Angular data-flow needs. With services, DI, and RxJS covered, the next section moves into routing with the Angular Router.

Next Lesson →

Angular Router Basics