Cours Angular · Module 7: RxJS

Les Subjects - Communication multidirectionnelle

2 min de lecture
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 : 3

Exemple 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. 1. En quoi un BehaviorSubject diffère-t-il d'un Subject classique ?

  2. 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 :

Articles utiles