ShMswi
ShMswi

Reputation: 159

Is It good to subscribe to an observable within another subscription handler?

I'm using Angular2 and I have a question about what is the best way to do if I have many observables. Can I put subscriptions inside each other or put each one in a different method and put the results in class properties?

Example :

ngOnInit() {
this.route.params**.subscribe**(params => {
   if (params['id']) {
    this.load = true;
     this.batchService.getPagesOfCurrentObject(params['id'], "10", "0")
       **.subscribe**(result => {
         this.stream = result;
         if (this.stream.length > 0) {
           this.stream.forEach(page => { this.batchService.getPageStreamById
           (page.pageId)**.subscribe**(pageStream => {
              let base64 = btoa(new Uint8Array(pageStream.data)
                 .reduce((data, byte) 
                    => data + String.fromCharCode(byte), ''));
               this.pages.push(base64 );

             })

             return;
           });
         }

     },
       error => this.errorService.setError(<any>error),
       () => this.load = false
       );
   }
 });

 try {
   this.customer = this.sharedService.processSelect.subscription.customer;
 } catch (err) {
   return;
 }
}

Upvotes: 4

Views: 4498

Answers (1)

atomrc
atomrc

Reputation: 2583

Having multiple observables is totally fine, this is what reactive programming is about :)

But here your problem is having too much subscribe. Keep in mind that subscribe is a way to create side effect. To have an easy to read code, you should try to use the least possible subscribe.

Your use case is the perfect use case for the mergeMap operator, that allows you to flatten nested observables.

Here what your code would look like

const response$ = this.route.params
  .mergeMap(params => {
    return this.batchService.getPagesOfCurrentObject(params['id'])
  })
  .mergeMap(stream => {
    return Rx.Observable.merge(stream.map(page => this.batchService.getPageStreamById(page.pageId))
  })
  .map(pageStream => /* do your stuff with pageStream, base64 ... */)

response$.subscribe(pageStreamData => pages.push(pageStreamData))

See how there is a single subscription that triggers the side-effect that will modify your app's state

Note that I voluntarily simplified the code (removed error handling and checks) for you to get the idea of how to do that.

I hope it will help you thinking in reactive programming :)

Upvotes: 5

Related Questions