change the source of observable at runtime (rxjs)

Viewed 243

i need to change the source of an observable with a swith .

this.su = this.appService._sub1.subscribe(data => {
  this.items.push(data);
});

//appService
  setSub(name) {
    if (name == 'A') {
      console.log('B');
      this._sub1 = this.sub2;
    } else if (name == 'B') {
      console.log('B');
      this._sub1 = this.sub3;
    }
    console.log(this._sub1);
  }

however, the source of the first observable keeps sending data, how can I do it?

Stackblitz link

https://stackblitz.com/edit/angular-ivy-evczcx?file=src/app/app.service.ts

2 Answers

Ultimately, I think you will want to use switchMap. You don't really want to switch the subscription, but rather the source.

It's cleaner if you design your service to expose observables, then have your components subscribe to them (ideally with AsyncPipe).

As a sample, something like this should work:

export class AppService {
  private source$ = new BehaviorSubject<SourceType>('frutas');
  private frutas = ['pera', 'manzana', 'platano', 'fresa'];
  private electronicos = ['celular', 'pc', 'cable'];

  private frutas$ = interval(2000).pipe(
    map(n => n % 4), 
    map(i => this.frutas[i])
  );

  private electronicos$ = interval(2000).pipe(
    map(n => n % 3), 
    map(i => this.electronicos[i])
  );

  data$ = this.source$.pipe(
    switchMap(source => source === 'frutas' ? this.frutas$ : this.electronicos$)
  );

  setSource(name: SourceType) {
    this.source$.next(name);
  }
}

Here's a working StackBlitz demo.

Swapping a reference to a subscription does nothing to the subscription itself. You need to unsubscribe. Also keep in mind, that interval produces a "hot" observable. Meaning it will push data to the stream wether someone has subscribed or not.

In real life, you would probably use something like httpClient.get() which is not "hot" (runs only when subscribed to, and completes once it's done). So it's not an issue usually, but with interval, you will end up with memory leaks and performance hits unless you manually stop the scheduler from running.

this._sub1.unsubscribe();
Related