Skip to content
Advertisement

avoid nested subscribe if there is a forkjoin inside

Here is my code in angular

this.service.save(body).subscribe(
    resp => {
       this.dialog.confirmation({
          message: 'save object successfully!'
       })
       .subscribe((ok) => {
            if(ok) {
               this.pro.status = resp.status;
            this.loadingData(resp);
            const s1 = this.service.getSummary(this.id);
            const s2 = this.service.getCost(this.id);
            forkJoin([s1, s2]).subscribe([r1, r2]) => {
               this.view = r1;
               this.list = r2;
            }
          }
        });
     }
);

So there are many levels of subscribe. Not only it is ugly also the result is wrong and I can’t not find it out by debugging. How can I rewrite it with rxjs operators?

Advertisement

Answer

You can simplify it using the RxJS operators, like the following:

// import { EMPTY, forkJoin } from 'rxjs';
// import { map, mergeMap } from 'rxjs/operators';

this.service
  .save(body)
  .pipe(
    mergeMap((result) =>
      // Merge the main observable with the dialog confirmation one..
      // and map it to an object that contains the result from both observables.
      this.dialog
        .confirmation({ message: 'save object successfully!' })
        .pipe(map((confirmed) => ({ result, confirmed })))
    ),
    mergeMap(({ result, confirmed }) => {
      if (confirmed) {
        this.pro.status = result.status;
        this.loadingData(result);
        const s1 = this.service.getSummary(this.id);
        const s2 = this.service.getCost(this.id);
        return forkJoin([s1, s2]);
      }
      // Don't emit any value, if the dialog is not confirmed:
      return EMPTY;
    })
  )
  .subscribe(([r1, r2]) => {
    this.view = r1;
    this.list = r2;
  });

Note: To handle the memory leaks, it’s highly recommended to unsubscribe from the observable when you don’t need it anymore, and this can be achieved based on your use cases, such as assigning the subscribe function result to a Subscription variable and calling unsubscribe in ngOnDestroy lifecycle hook, or using a Subject with takeUntil operator and calling next/complete functions in ngOnDestroy.

And here is how to use the unsubscribe method for example:

// import { Subscription } from 'rxjs';

@Component({...})
export class AppComponent implements OnInit, OnDestroy {
    subscription: Subscription 
    ngOnInit(): void {
      this.subscription = this.service.save(body)
        // >>> pipe and other RxJS operators <<<
        .subscribe(([r1, r2]) => {
          this.view = r1;
          this.list = r2;
        });
    }
    ngOnDestroy() {
        this.subscription.unsubscribe()
    }
}

You can read more about that here: https://blog.bitsrc.io/6-ways-to-unsubscribe-from-observables-in-angular-ab912819a78f

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement