Organize subscription chains with pipes

Often, two or more observables depend upon one another for execution. This can lead to chained subscriptions. Take this real-world example:

this.openInvalidPeriodDialog$(dialog).subscribe(dialog => {
  dialog.afterClosed().subscribe(jumpToLatestPeriod => {
    if (jumpToLatestPeriod) {
      this.periodService.getLatestPeriod().subscribe(latestPeriod => {
        this.analysisService.getPreliminaryPeriodId$(federalReserveId, analysisId, latestPeriod.id)
        .subscribe(periodId => this.sessionService.setQualitativePeriod(periodId ?? latestPeriod.id))
      });
    }
  });
});

The multiple subscribes() might be written in a more descriptive chain with a pipe and use of switchMap() and filter().

this.openInvalidPeriodDialog$(rejectionDialog)
  .pipe(
      switchMap(invalidPeriodDialog => invalidPeriodDialog.afterClosed()),
      filter(jumpToLatestPeriod => jumpToLatestPeriod),
      switchMap(() => this.periodService.getLatestPeriod()),
      switchMap(latestPeriod => forkJoin({
          preliminaryPeriod: this.analysisService.getPreliminaryPeriodId$(federalReserveId, analysisId, latestPeriod.id),
          latestPeriod: of(latestPeriod.id)
      }))
  ).subscribe(periodToUse =>
      this.sessionService.setQualitativePeriod(periodToUse.preliminaryPeriod ?? periodToUse.latestPeriod)
  );

The refactored example makes explicit that further subscriptions happen only when the boolean filter passes and keeps a single subscription() line that describes what actually needs to happen after all observables have been properly mapped and resolved.