J'ai un observable qui fait son travail et fonctionne bien. Cependant, il a plusieurs couches de nidification qui ne semblent pas très RxJS'y et semblent pouvoir être aplaties

const filteredEntries$ = this.filterForm.controls.day.valueChanges.pipe(
  switchMap((selectedDayId: string) =>
    this.entries$.pipe(
      map((entries: Entry[]) =>
        this.entriesForDay$(entries, selectedDayId)
      )
    )
  )
)

Je voudrais supprimer le tube imbriqué interne pour que les choses restent plus claires:

const filteredEntries$ = this.filterForm.controls.day.valueChanges.pipe(
  switchMap((selectedDayId: string) =>
    this.entries$
  ),
  map((entries: Entry[]) =>
    // selectedDayId is not available in this scope :( 🛑
    this.entriesForDay$(entries, selectedDayId)
  )
)

Est-il possible d'aplatir l'observable comme ceci et si oui, comment puis-je passer la valeur de selectedDayId dans l'instruction finale .map?

Torsion du tracé ...

Il n'y a rien de tel que d'écrire une question SO pour y répondre. Je suppose que la solution est que vous transmettez le selectedDayId et le renvoyez à partir de la première instruction switch. Ma question est donc de savoir comment faire cela avec élégance plutôt que de tâtonner avec des tableaux ou des objets. Existe-t-il un moyen d'assigner en masse les valeurs de retour directement dans les paramètres de la méthode suivante (comme indiqué ci-dessous):

const filteredEntries$ = this.filterForm.controls.day.valueChanges.pipe(
  switchMap((selectedDayId: string) =>
    this.entries$, selectedDayId // is there a way to return two values 
                                 // directly to the next method?
  ),
  map((entries: Entry[], selectedDayId) =>
    this.entriesForDay$(entries, selectedDayId)
  )
)
1
Peter Nixey 23 sept. 2020 à 20:58

2 réponses

Meilleure réponse

Vous n'avez pas besoin de switchMap dans votre cas. Vous pouvez combiner les flux valueChanges et entries$.

const filteredEntries$ = combineLatest([
  this.filterForm.controls.day.valueChanges,
  this.entries$
]).pipe(
  map(([selectedDayId, entries]) =>
    this.entriesForDay$(entries, selectedDayId)
  )
)

En général, je pense qu'avoir une couche imbriquée est parfaitement bien. Si l'imbrication devient trop profonde, je suggérerais de déplacer une partie du code dans des fonctions supplémentaires.

const filteredEntries$ = this.filterForm.controls.day.valueChanges.pipe(
  switchMap((selectedDayId: string) => this.entriesFor$(selectedDayId))
)

const entriesFor$ = (selectedDayId: string) => this.entries$.pipe(
  map((entries: Entry[]) => this.entriesForDay$(entries, selectedDayId))
)
1
fridoo 23 sept. 2020 à 18:33

Une solution possible consiste à utiliser combineLatest:

Lorsqu'un observable émet une valeur, émettez la dernière valeur émise de chaque

Votre code serait:

const filteredEntries$ = this.filterForm.controls.day.valueChanges.pipe(
  switchMap((selectedDayId: string) =>
    combineLatest(this.entries$, of(selectedDayId))
  ),
  map((entries: Entry[], selectedDayId) =>
    this.entriesForDay$(entries, selectedDayId)
  )
)
1
Tal Ohana 23 sept. 2020 à 18:33