Angular course Β· Module 7: RxJS
Subjects - Multi-directional Communication
In this lesson2
Subjects are special Observables that can both emit and receive values - like a ninja command center.
Types of Subjects
import { Subject, BehaviorSubject, ReplaySubject, AsyncSubject } from 'rxjs';
// Subject - basic, no memory
const subject = new Subject<string>();
subject.subscribe(v => console.log('A:', v));
subject.next('Hello'); // A: Hello
subject.subscribe(v => console.log('B:', v));
subject.next('World'); // A: World, B: World
// B did not receive 'Hello' - there was no subscription
// BehaviorSubject - remembers the last value
const behavior = new BehaviorSubject<number>(0); // Requires initial value
behavior.subscribe(v => console.log('A:', v)); // A: 0 (immediately!)
behavior.next(1); // A: 1
behavior.subscribe(v => console.log('B:', v)); // B: 1 (last value!)
behavior.next(2); // A: 2, B: 2
// ReplaySubject - remembers the last n values
const replay = new ReplaySubject<number>(2); // Remembers last 2
replay.next(1);
replay.next(2);
replay.next(3);
replay.subscribe(v => console.log(v)); // 2, 3 (last 2)
// AsyncSubject - emits only the last value on complete
const async = new AsyncSubject<number>();
async.next(1);
async.next(2);
async.subscribe(v => console.log(v)); // Nothing
async.next(3);
async.complete(); // Now: 3Practical Example - State Service
@Injectable({ providedIn: 'root' })
export class NotificationService {
private notificationsSubject = new BehaviorSubject<Notification[]>([]);
// We expose only the Observable (readonly)
readonly notifications$ = this.notificationsSubject.asObservable();
// Current value available synchronously
get currentNotifications(): Notification[] {
return this.notificationsSubject.getValue();
}
addNotification(notification: Notification): void {
const current = this.currentNotifications;
this.notificationsSubject.next([...current, notification]);
}
removeNotification(id: number): void {
const filtered = this.currentNotifications.filter(n => n.id !== id);
this.notificationsSubject.next(filtered);
}
clearAll(): void {
this.notificationsSubject.next([]);
}
}
// Usage in a component
@Component({
template: `
@for (notification of notifications$ | async; track notification.id) {
<div class="notification" (click)="remove(notification.id)">
{{ notification.message }}
</div>
}
`
})
export class NotificationListComponent {
notifications$ = inject(NotificationService).notifications$;
private notificationService = inject(NotificationService);
remove(id: number): void {
this.notificationService.removeNotification(id);
}
}Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. How does a BehaviorSubject differ from a regular Subject?
2. What characterizes a ReplaySubject?
These are 2 of 4 questions for this lesson. Solve the rest in the game.
Hands-on tasks in the game
- Code editor
Complete the user state service: it needs a Subject with an initial value that remembers the last value and returns it with getValue().
- Horizontal ordering
Arrange the creation of a BehaviorSubject with an initial value of 0:
- Vertical ordering
Arrange the lines of the method that adds a notification to a service based on a BehaviorSubject: