RxJS (Reactive Extensions for JavaScript) is a core part of Angular. It allows handling asynchronous data streams using Observables, operators, and Subjects. Understanding RxJS is essential for working with HTTP requests, forms, events, and real-time data.
1. Observables & Subscribers
An Observable represents a stream of data over time. Components subscribe to it to receive values.
import { Observable } from 'rxjs';
const numbers$ = new Observable<number>(observer => {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
});
numbers$.subscribe({
next: (value) => console.log(value),
complete: () => console.log('Completed')
});
2. Operators
Operators transform, filter, or combine Observables.
2.1 map, filter, tap
import { of } from 'rxjs';
import { map, filter, tap } from 'rxjs/operators';
of(1, 2, 3, 4).pipe(
filter(x => x % 2 === 0),
map(x => x * 2),
tap(x => console.log('Value after map:', x))
).subscribe();
2.2 debounceTime
Useful for search inputs to limit rapid API calls:
import { fromEvent } from 'rxjs';
import { debounceTime, map } from 'rxjs/operators';
const searchBox = document.getElementById('search');
fromEvent(searchBox, 'input').pipe(
debounceTime(300),
map((event: any) => event.target.value)
).subscribe(value => console.log(value));
2.3 switchMap, mergeMap, concatMap
Used to handle nested Observables (like HTTP calls):
// switchMap - cancels previous request
source$.pipe(
switchMap(value => http.get(`api/data/${value}`))
).subscribe();
// mergeMap - runs all requests concurrently
source$.pipe(
mergeMap(value => http.get(`api/data/${value}`))
).subscribe();
// concatMap - runs requests sequentially
source$.pipe(
concatMap(value => http.get(`api/data/${value}`))
).subscribe();
2.4 forkJoin
Waits for multiple Observables to complete and returns results as an array:
forkJoin({
users: http.get('/api/users'),
posts: http.get('/api/posts')
}).subscribe(result => {
console.log(result.users, result.posts);
});
2.5 combineLatest
Combines latest values from multiple Observables:
combineLatest([obs1$, obs2$]).subscribe(([val1, val2]) => {
console.log(val1, val2);
});
3. Subjects & BehaviorSubject
Subject
A Subject is both an Observable and Observer. It can emit values to multiple subscribers:
import { Subject } from 'rxjs';
const subject = new Subject<number>();
subject.subscribe(value => console.log('Subscriber 1:', value));
subject.subscribe(value => console.log('Subscriber 2:', value));
subject.next(1);
subject.next(2);
BehaviorSubject
Keeps the latest value and emits it immediately to new subscribers:
import { BehaviorSubject } from 'rxjs';
const behavior = new BehaviorSubject<number>(0);
behavior.subscribe(val => console.log('Subscriber 1:', val));
behavior.next(1);
behavior.subscribe(val => console.log('Subscriber 2:', val)); // gets 1 immediately
4. AsyncPipe
Angular provides async pipe to automatically subscribe and unsubscribe from Observables in templates:
<ul>
<li *ngFor="let user of users$ | async">{{ user.name }}</li>
</ul>
users$ = this.http.get<User[]>('/api/users');
No need to manually subscribe or unsubscribe in the component.
Summary
- Observables represent asynchronous streams; subscribe to receive values.
- Operators (map, filter, tap, debounceTime, switchMap, mergeMap, concatMap, forkJoin, combineLatest) transform and control streams.
- Subjects allow multicasting of values to multiple subscribers.
- BehaviorSubject stores the latest value for new subscribers.
- AsyncPipe automatically handles subscriptions in templates.