Subjects are special Observables that can both emit and receive values - like a ninja command center.
1import { Subject, BehaviorSubject, ReplaySubject, AsyncSubject } from 'rxjs';
2
3// Subject - basic, no memory
4const subject = new Subject<string>();
5subject.subscribe(v => console.log('A:', v));
6subject.next('Hello'); // A: Hello
7subject.subscribe(v => console.log('B:', v));
8subject.next('World'); // A: World, B: World
9// B did not receive 'Hello' - there was no subscription
10
11// BehaviorSubject - remembers the last value
12const behavior = new BehaviorSubject<number>(0); // Requires initial value
13behavior.subscribe(v => console.log('A:', v)); // A: 0 (immediately!)
14behavior.next(1); // A: 1
15behavior.subscribe(v => console.log('B:', v)); // B: 1 (last value!)
16behavior.next(2); // A: 2, B: 2
17
18// ReplaySubject - remembers the last n values
19const replay = new ReplaySubject<number>(2); // Remembers last 2
20replay.next(1);
21replay.next(2);
22replay.next(3);
23replay.subscribe(v => console.log(v)); // 2, 3 (last 2)
24
25// AsyncSubject - emits only the last value on complete
26const async = new AsyncSubject<number>();
27async.next(1);
28async.next(2);
29async.subscribe(v => console.log(v)); // Nothing
30async.next(3);
31async.complete(); // Now: 31@Injectable({ providedIn: 'root' })
2export class NotificationService {
3 private notificationsSubject = new BehaviorSubject<Notification[]>([]);
4
5 // We expose only the Observable (readonly)
6 readonly notifications$ = this.notificationsSubject.asObservable();
7
8 // Current value available synchronously
9 get currentNotifications(): Notification[] {
10 return this.notificationsSubject.getValue();
11 }
12
13 addNotification(notification: Notification): void {
14 const current = this.currentNotifications;
15 this.notificationsSubject.next([...current, notification]);
16 }
17
18 removeNotification(id: number): void {
19 const filtered = this.currentNotifications.filter(n => n.id !== id);
20 this.notificationsSubject.next(filtered);
21 }
22
23 clearAll(): void {
24 this.notificationsSubject.next([]);
25 }
26}
27
28// Usage in a component
29@Component({
30 template: \`
31 @for (notification of notifications$ | async; track notification.id) {
32 <div class="notification" (click)="remove(notification.id)">
33 {{ notification.message }}
34 </div>
35 }
36 \`
37})
38export class NotificationListComponent {
39 notifications$ = inject(NotificationService).notifications$;
40 private notificationService = inject(NotificationService);
41
42 remove(id: number): void {
43 this.notificationService.removeNotification(id);
44 }
45}