Flattening Operators
Flattening operators handle Observables that emit Observables (higher-order Observables). They subscribe to inner Observables and flatten the result.
switchMap — Cancel Previous
Cancels the previous inner Observable when a new value arrives. Ideal for type-ahead search.
import { switchMap } from 'rxjs/operators';
this.searchInput.valueChanges.pipe(
debounceTime(300),
switchMap(query => this.searchService.search(query))
).subscribe(results => {
this.results = results;
});
When the user types a new character, the previous search request is cancelled and a new one starts.
mergeMap — Concurrent
Runs all inner Observables concurrently without waiting. Ideal for parallel requests.
import { mergeMap } from 'rxjs/operators';
this.userIds$.pipe(
mergeMap(ids => this.http.get<User[]>(`/api/users?ids=${ids.join(',')}`))
).subscribe(users => {
this.users = users;
});
concatMap — Sequential
Runs inner Observables one at a time, in order. Ideal for dependent requests.
import { concatMap } from 'rxjs/operators';
this.saveRequests$.pipe(
concatMap(request => this.http.post('/api/save', request))
).subscribe(result => {
console.log('Saved:', result);
});
Flattening Operator Comparison
| Operator | Behavior | Use When |
|---|---|---|
switchMap |
Cancel previous, switch to new | Search, autocomplete |
mergeMap |
All concurrent | Parallel requests |
concatMap |
Sequential, in order | Dependent requests |
exhaustMap |
Ignore new until current completes | Form submissions |
Practical Example: Search with switchMap
@Component({
selector: 'app-search',
template: `
<input [formControl]="searchControl" placeholder="Search...">
<p *ngFor="let result of results">{{ result.name }}</p>
`,
})
export class SearchComponent implements OnInit {
searchControl = new FormControl('');
results: SearchResult[] = [];
ngOnInit(): void {
this.searchControl.valueChanges.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap(query => this.searchService.search(query)),
catchError(() => of([]))
).subscribe(results => {
this.results = results;
});
}
}
Joining Operators
Joining operators combine multiple Observables into one.
combineLatest — Latest from All
Emits whenever any source emits, using the latest value from each source.
import { combineLatest } from 'rxjs';
const price$ = this.getPrice();
const quantity$ = this.getQuantity();
combineLatest([price$, quantity$]).pipe(
map(([price, quantity]) => price * quantity)
).subscribe(total => {
this.total = total;
});
forkJoin — Wait for All to Complete
Emits once when all source Observables complete. Ideal for parallel HTTP requests.
import { forkJoin } from 'rxjs';
forkJoin({
users: this.http.get<User[]>('/api/users'),
posts: this.http.get<Post[]>('/api/posts'),
comments: this.http.get<Comment[]>('/api/comments'),
}).subscribe(({ users, posts, comments }) => {
this.users = users;
this.posts = posts;
this.comments = comments;
});
withLatestFrom — Secondary Values
Emits when the primary source emits, combining with the latest value from secondary sources.
import { withLatestFrom } from 'rxjs/operators';
this.clicks$.pipe(
withLatestFrom(this.user$)
).subscribe(([clickEvent, user]) => {
console.log('User', user.name, 'clicked at', clickEvent.clientX);
});
Joining Operator Comparison
| Operator | Behavior | Use When |
|---|---|---|
combineLatest |
Emits on any source emit | Multiple live streams |
forkJoin |
Emits once on all complete | Parallel HTTP requests |
withLatestFrom |
Primary + secondary latest | Click + context |
zip |
Pairs emissions by index | Synchronized streams |
Quiz
1. Which flattening operator cancels the previous inner Observable?
2. Which operator should you use for parallel HTTP requests?
3. What does combineLatest do?
Flashcards
Question
Which operator cancels previous inner Observable?
Click to reveal answer
Answer
switchMap — cancels previous, switches to new. Ideal for search.
Question
Which operator for parallel HTTP requests?
Click to reveal answer
Answer
forkJoin — waits for all to complete, emits final values together.
Question
What does combineLatest do?
Click to reveal answer
Answer
Emits whenever any source emits, using the latest value from each source.
Revision Notes
Key Takeaways
- 1. switchMap cancels previous inner Observable
- 2. mergeMap runs concurrently, concatMap sequentially
- 3. forkJoin waits for all to complete
- 4. combineLatest emits on any source emission
Interview Tips
- • Explain when to use each flattening operator
- • Be ready to describe forkJoin for parallel requests
- • Mention combineLatest for joining live streams
Cheat Sheet
Combination Operators Cheat Sheet
switchMap (cancel previous):
switchMap(query => this.searchService.search(query))
mergeMap (concurrent):
mergeMap(ids => this.http.get(url))
concatMap (sequential):
concatMap(request => this.http.post(url, request))
forkJoin (parallel HTTP):
forkJoin({ users: this.http.get('/api/users'), posts: this.http.get('/api/posts') })
combineLatest (latest from all):
combineLatest([price$, quantity$]).pipe(map(([p, q]) => p * q))