LearnAI ToolsCareerPractice BuildsPlayContact
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.

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