1. Transformation

map


L'opérateur map prend les valeurs d'un observable, les transforme, et crée un nouvel observable qui émet les valeurs transformées.


Prenons un exemple courant en Angular: on récupère une réponse du back-end avec HttpClient, et on veut simplement en extraire une propriété et ne retourner que celle-ci:


  import { map } from 'rxjs/operators';

  interface Response<T> {
    success: boolean;
    data: T;
  }

  (...)

  public getBooks(): Observable<Book[]> {
      return httpClient.get<Response<Book[]>>('/books').pipe(
        map((res: Response<Book[]>) => res.data) // only returns 'data'
    );
  }


switchMap


switchMap reçoit les valeurs émises par un observable, et retourne un nouvel observable provenant d'une source différente.


Voici un exemple commun d'utilisateur de switchMap:

Vous avez une liste d'ids de livres dans un select. Quand l'utilisateur sélectionne une valeur, selectedId$ émet une nouvelle valeur.

Vous avez besoin de récupérer le livre complet, en vous basant sur la nouvelle valeur de selectedId$.


  import { switchMap } from 'rxjs/operators';

  (...)
  selectedId$: Subject<string> = new Subject();
  selectedBook: Book;

  getBook(): void {
    this.selectedId$.pipe( // Listen to selectedId$ changes
      switchMap(id: string) => this.booksService.getBook(id)) // Redirects to another observable (http request)
    ).subscribe(book => this.selectedBook = book); // Get a book
  }


2. Filtering

filter


filter est un opérateur qui émet uniquement les valeurs respectant les conditions décrites. Cela peut être utile pour éviter de souscrire à un observable si cela n'est pas nécessaire.


Par exemple, peut-être que vous ne voulez pas souscrire à l'observable selectedBook$ quand sa valeur est null ou undefined. Dans ce cas, vous pouvez utiliser filter :


  import { filter } from 'rxjs/operators';

  (...)

  selectedBook$: Observable<Book> = this.booksService.book$;

  getBook(): void {
    this.selectedBook$.pipe(
      filter(book => !!book) // returns false if book is null or undefined, and stops the observable here
    ).subscribe(book => this.book = book);
  }


distinctUntilChanged


Toujours sur le même exemple, vous ne voulez peut-être pas passer deux fois dans le subscribe quand la valeur de selectedBook$ ne change pas.


Vous pouvez utiliser distinctUntilChanged pour cela :


  import { distinctUntilChanged } from 'rxjs/operators';

  (...)

  selectedBook$: Observable<Book> = this.booksService.book$;

  getBook(): void {
    this.selectedBook$.pipe(
      distinctUntilChanged() // stops if the previous and current values are the same
    ).subscribe(book => this.book = book);
  }


A savoir : distinctUntilChanged peut prendre une fonction en argument.


  getBook(): void {
    this.selectedBook$.pipe(
      distinctUntilChanged((previousValue: Book, currentValue: Book) => {
        return previousValue.id === currentValue.id; // will stops if ids are the same
      })
    ).subscribe(book => this.book = book);
  }


Il existe un opérateur pour de simples opérations comme ci-dessus : distinctUntilKeyChanged


  import { distinctUntilKeyChanged } from 'rxjs/operators';

  (...)

  getBook(): void {
    this.selectedBook$.pipe(
      distinctUntilKeyChanged('id') // does the same as the previous example
    ).subscribe(book => this.book = book);
  }


takeUntil


takeUntil est un opérateur qui émet des valeurs jusqu'à ce que l'observable fourni émette une valeur.


Exemple: gérer les unsubscriptions.

  import { takeUntil } from 'rxjs/operators';

  (...)

  this.dataService.data$.pipe(
    takeUntil(this.destroyed$) // will unsubscribe when destroyed$ completes
  ).subscribe(data => this.data = data);


3. Combination

combineLatest


Quand un des observables émet une valeur, combineLatest émet la dernière valeur de chaque.

Soyez vigilant, combineLatest n'émettra aucune valeur tant que chacun des observables n'aura pas émis une valeur.


Cette opérateur est utile quand par exemple on veut déclencher une recherche multi-critères basée sur plusieurs inputs :


  import { combineLatest } from 'rxjs';

  (...)

  combineLatest([
      this.searchTextCtrl.valueChanges,
      this.dateRangeCtrl.valueChanges,
      this.author.valueChanges
    ]).subscribe(([
      searchText,
      dateRange,
      author
    ]) => this.results = this.getFilteredResults(searchText, dateRange, author));


pairwise


pairwise permet d'obtenir dans un tableau la valeur précédente et la valeur actuelle d'un observable.


Par exemple, nous avons un observable selectedBook$, qui émet une nouvelle valeur à chaque fois qu'il change.

Nous voulons effectuer une comparaison de la valeur précédente par rapport à l'actuelle. Nous pouvons faire ainsi :


  import { pairwise } from 'rxjs/operators';

  (...)

  this.selectedBook$.pipe( // For example, the previous value was 'Harry Potter 1' and the new one is '1984'
    pairwise()
  ).subscribe(([previousValue, currentValue]) => { // ['Harry Potter 1', '1984']
    // Do something here
  });


4. Utility

tap


tap permet d'effectuer des actions sur un flux d'observable sans modifier ni altérer le flux original. Les valeurs The values "traversent" l'opérateur tap jusqu'au prochain opérateur ou subscriber.


  import { tap } from 'rxjs/operators';

  (...)

  public getBooks(): Observable<Book[]> {
    return httpClient.get<Book[]>('/books').pipe(
      tap((books) => this.snackbar.open(`${books.length} books received!`)) // action performed without altering the observable
    );
  }