Cours Angular · Module 7: RxJS
Les Subjects - Communication multidirectionnelle
Dans cette leçon2
Les Subjects sont des Observables spéciaux qui peuvent à la fois émettre et recevoir des valeurs - comme un centre de commandement ninja.
Les types de Subjects
1import { Subject, BehaviorSubject, ReplaySubject, AsyncSubject } from 'rxjs';
2
3// Subject - basique, sans mémoire
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 n'a pas reçu 'Hello' - il n'y avait pas d'abonnement
10
11// BehaviorSubject - se souvient de la dernière valeur
12const behavior = new BehaviorSubject<number>(0); // Nécessite une valeur initiale
13behavior.subscribe(v => console.log('A:', v)); // A: 0 (immédiatement !)
14behavior.next(1); // A: 1
15behavior.subscribe(v => console.log('B:', v)); // B: 1 (dernière valeur !)
16behavior.next(2); // A: 2, B: 2
17
18// ReplaySubject - se souvient des n dernières valeurs
19const replay = new ReplaySubject<number>(2); // Se souvient des 2 dernières
20replay.next(1);
21replay.next(2);
22replay.next(3);
23replay.subscribe(v => console.log(v)); // 2, 3 (les 2 dernières)
24
25// AsyncSubject - n'émet que la dernière valeur au complete
26const async = new AsyncSubject<number>();
27async.next(1);
28async.next(2);
29async.subscribe(v => console.log(v)); // Rien
30async.next(3);
31async.complete(); // Maintenant : 3Exemple pratique - Un service d'état
1@Injectable({ providedIn: 'root' })
2export class NotificationService {
3 private notificationsSubject = new BehaviorSubject<Notification[]>([]);
4
5 // On n'expose que l'Observable (readonly)
6 readonly notifications$ = this.notificationsSubject.asObservable();
7
8 // Valeur actuelle disponible de façon synchrone
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// Utilisation dans un composant
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}Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. En quoi un BehaviorSubject diffère-t-il d'un Subject classique ?
2. Qu'est-ce qui caractérise un ReplaySubject ?
Voici 2 des 4 questions de cette leçon. Réponds aux autres dans le jeu.
Tâches pratiques dans le jeu
- Éditeur de code
Complète le service d'état de l'utilisateur : il faut un Subject avec une valeur initiale, qui retient la dernière valeur et la renvoie avec getValue().
- Tri horizontal
Ordonne la création d'un BehaviorSubject avec une valeur initiale de 0 :
- Tri vertical
Ordonne les lignes de la méthode qui ajoute une notification à un service basé sur un BehaviorSubject :