RxJS & Observables: Angular’s Reactive Heart
An Observable is a stream of values that arrive over time — and almost everything async in Angular (HTTP, the router, forms) hands you one.
What you will learn
- Explain what an Observable is and how it differs from a single value
- Subscribe and unsubscribe correctly
- Reshape a stream with map, filter and the async pipe
A value that arrives over time
You already know a normal value: it is there right now (name = "Asha"). An Observable is different — it is a stream: zero, one, or many values that arrive over time. Think of a normal value as a single letter in your hand, and an Observable as a mailbox that may receive letters now, in a second, or never.
RxJS is the library Angular uses to work with these streams (the name means “Reactive Extensions for JavaScript”). You cannot avoid it: HttpClient returns an Observable, the router gives route changes as an Observable, and reactive forms report value changes as an Observable. Learning RxJS is what lets you read and write real Angular code.
| A normal value | An Observable | |
|---|---|---|
| When you get it | Right now | Later, possibly many times |
| How many values | Exactly one | Zero, one, or many over time |
| How you read it | Just use it | You subscribe to it |
| Examples | a string, a number | an HTTP reply, clicks, a timer |
Subscribe to listen to the stream
An Observable does nothing until you subscribe — that is like opening your mailbox to start receiving letters. The function you pass runs each time a value arrives.
// a simple stream that emits three numbers
import { of } from 'rxjs';
const numbers = of(1, 2, 3);
numbers.subscribe(value => {
console.log('Got:', value);
});Note: Output:
Got: 1
Got: 2
Got: 3
of(1, 2, 3) makes an Observable that emits those values in order. subscribe runs the function once per value, so we see three lines. Without subscribe, nothing would happen at all.
Reshape the stream with operators
An operator is a tool that transforms a stream as values pass through, inside a .pipe(...). The two you will meet first are map (change each value) and filter (keep only some). They mirror the array methods you already know — but they work on values arriving over time.
import { of } from 'rxjs';
import { map, filter } from 'rxjs/operators';
of(1, 2, 3, 4)
.pipe(
filter(n => n % 2 === 0), // keep evens
map(n => n * 10) // multiply each by 10
)
.subscribe(v => console.log(v));Note: Output:
20
40
The stream 1,2,3,4 first passes through filter (only 2 and 4 survive), then through map (×10), giving 20 and 40. Operators run left to right, each handing its result to the next.
Subjects: streams you push values into
Sometimes you want to create a stream and push values into it yourself — for example, to share live data between components. A Subject is an Observable you can also feed. A BehaviorSubject is the same but remembers its latest value and gives it to anyone who subscribes — perfect for current state like “the logged-in user”.
import { BehaviorSubject } from 'rxjs';
const count = new BehaviorSubject(0); // starts holding 0
count.subscribe(v => console.log('A sees', v));
count.next(1); // push a new value
count.next(2);Note: Output:
A sees 0
A sees 1
A sees 2
The subscriber immediately gets the current value (0), then every new value pushed with next(...). This is the simplest way to share changing state across an app from a service.
The async pipe: subscribe for you
Subscribing by hand means you must also unsubscribe later (in ngOnDestroy) or risk a memory leak. Angular’s async pipe does both for you: it subscribes when the template needs the value and unsubscribes automatically when the component is destroyed.
// component class
import { interval } from 'rxjs';
export class TimerComponent {
seconds$ = interval(1000); // emits 0,1,2,3… every second
}<!-- template: the async pipe subscribes and cleans up -->
<p>Seconds passed: {{ seconds$ | async }}</p>Note: Output:
Seconds passed: 0 (then 1, 2, 3… every second)
The | async pipe subscribes to seconds$, shows each value, and unsubscribes when the component leaves — no manual cleanup. The $ on the end of the name is a common convention meaning “this is an Observable”.
Watch out: When you subscribe by hand (not via the async pipe), you must unsubscribe in ngOnDestroy, or the subscription keeps running after the component is gone — a memory leak. The async pipe avoids this entirely, so prefer it when you can.
Tip: A useful first set of operators: map (transform), filter (keep some), debounceTime (wait until typing pauses — great for search boxes), and switchMap (swap to a new inner stream, e.g. fire a new HTTP call per keystroke and cancel the old one).
Q. What is the key difference between a normal value and an Observable?
✍️ Practice
- Use
of(10, 20, 30)andsubscribeto log each value. - Pipe a stream through
mapto double every value, then log the results with the async pipe in a template.
🏠 Homework
- Create a BehaviorSubject in a service that holds a message string, update it with
next(...)from a button, and display it in two different components using the async pipe.