Chapter 9.5☕ 15 min read

Subjects

Subjects are both Observable and Observer. They are the foundation of multicasting and state management in Angular services.

01What is a Subject

A Subject is a special type of Observable that is BOTH an Observable (you can subscribe) AND an Observer (you can push values).

"Subject = announcement speaker — you can listen AND you can speak."

import { Subject } from 'rxjs';

// Create a Subject
const notification$ = new Subject();

// Subscribe to it (like Observable)
notification$.subscribe(msg => console.log('Listener 1:', msg));

// Push values to it (like Observer)
notification$.next('🍗 Biryani ready!');
// Listener 1: 🍗 Biryani ready!

// Late subscribers miss previous values
notification$.next('🥘 New curry added!');
// Listener 1: 🥘 New curry added!
// New subscriber below MISSES "Biryani ready!"
notification$.subscribe(msg => console.log('Listener 2:', msg));

Key facts about Subjects:

  • Used for cross-component communication (service → multiple components)
  • Multicast — one Subject, many subscribers share same execution
  • New subscribers miss previous values (except BehaviorSubject/ReplaySubject)
  • Don't forget to complete() when done to avoid memory leaks
02Subject — Basic

Subject is the basic type — no replay, no initial value. New subscribers only get values emitted AFTER they subscribe.

import { Subject } from 'rxjs';

const subject = new Subject();

// Late subscriber — misses 1 and 2
setTimeout(() => {
  subject.subscribe(v => console.log('Late:', v)); // Only sees 3
}, 1000);

subject.next(1);
subject.next(2);
setTimeout(() => subject.next(3), 2000);

"Subject = live radio — jo abhi bol rahe wo sunao, purana nahi."

Use cases for Subject:

  • Event bus for one-time notifications
  • Button click events, form submit events
  • Any "fire and forget" event where history doesn't matter

⚠️ Best practice: Always expose Subject as Observable to prevent external code from calling .next():

private refreshSubject = new Subject();

// Public as Observable only — components can subscribe but not emit
refresh$ = this.refreshSubject.asObservable();

// Only this service can call next()
triggerRefresh() {
  this.refreshSubject.next();
}
03BehaviorSubject — Has Current Value

BehaviorSubject is the most used Subject type. It requires an initial value and replays the LAST value to new subscribers.

import { BehaviorSubject } from 'rxjs';

// REQUIRES initial value
const userSubject = new BehaviorSubject(null);

// Subscribe immediately gets current value
userSubject.subscribe(user => console.log('User:', user));
// Output: User: null (initial value)

// Push a new value
userSubject.next({ id: 1, name: 'Shaik' });
// Output: User: { id: 1, name: 'Shaik' }

// New subscriber gets LAST value immediately
setTimeout(() => {
  userSubject.subscribe(user => console.log('Late:', user));
  // Output: Late: { id: 1, name: 'Shaik' } — gets latest immediately!
}, 5000);

"BehaviorSubject = DVR — join late bhi ho, last episode dikh jayega."

Why BehaviorSubject is the MOST USED Subject in Angular:

  • All components always have the current state — even if they subscribe late
  • Initial value prevents "undefined" errors
  • .getValue() — get current value synchronously (for imperative use)

BehaviorSubject is the foundation of the service state management pattern in Angular.

04ReplaySubject — Replay N Values

ReplaySubject replays a configurable number of past values to new subscribers.

import { ReplaySubject } from 'rxjs';

// ReplaySubject(bufferSize) — replay last N values
const chatMessages$ = new ReplaySubject(3); // Replay last 3

chatMessages$.next('Hello');
chatMessages$.next('Kya haal hai?');
chatMessages$.next('Biryani khao?');
chatMessages$.next('Chalo khaate hain!');

// New subscriber gets last 3 messages
chatMessages$.subscribe(msg => console.log(msg));
// Output: 'Kya haal hai?', 'Biryani khao?', 'Chalo khaate hain!'

"ReplaySubject = highlights reel — last 3 moments dikhao."

Use cases for ReplaySubject:

  • Chat message history
  • Audit logs
  • Notification feed (last N items)
  • Any scenario where late subscribers should see recent history

With Infinity buffer: new ReplaySubject(Infinity) — replays ALL past values (use carefully, memory grows unbounded).

05AsyncSubject — Last Value Only After Complete

AsyncSubject emits ONLY the LAST value, and ONLY AFTER complete() is called.

import { AsyncSubject } from 'rxjs';

const result$ = new AsyncSubject();

result$.subscribe(v => console.log('Result:', v));
// No output yet — still waiting for complete()

result$.next(1);
result$.next(2);
result$.next(42); // This will be the LAST value

// Nothing emitted yet! No complete() called

result$.complete();
// NOW output: Result: 42 (only the LAST value)

"AsyncSubject = exam result — sab wait karo, result ek baar aayega."

Rarely used in Angular — but good to know.

Use cases: Result of a computation that runs once and completes (like a Promise alternative).

Subject types comparison:

Subject          — No replay, no initial value
BehaviorSubject  — Replays 1 (last value), requires initial value
ReplaySubject    — Replays N (configurable), optional initial value
AsyncSubject     — Replays 1 (last), but ONLY after complete()

Key Takeaways

  • ✅ Subject = BOTH Observable and Observer — subscribe to listen, .next() to emit
  • ✅ Subject — no replay (late subscribers miss previous values), for events/notifications
  • ✅ BehaviorSubject — replays last value, REQUIRES initial value, MOST USED in Angular services
  • ✅ ReplaySubject(N) — replays last N values, for chat/log history
  • ✅ AsyncSubject — emits last value only after complete(), like a Promise