0

I'm developing an angular 7 app, I know that nested subscribe functions are an anti pattern but using correctly the transformation operators (like mergeMap, switchMap ...) inside a pipe function I could always avoid it. I'm facing a situation in which I can't understand how the inner observable works. I have a form of filters which are fully intialized after an event signaled by an observable, after this event I have to listen form changes via .valueChanges on the formGroup, format the filters and finally filter the results.

this.filters.categoriesReady.asObservable()
      .pipe(
        tap((categories) => {
          this._createControlsCategories(categories);
          this.categories = categories;
          console.log('higher order observable');
        }),
        switchMap(() => this.filterForm.valueChanges),
        switchMap(filtersRaw => this._formatFilters(filtersRaw)),
        takeUntil(this.unsubscribe)
      )
      .subscribe(
        filtersFormatted => {
          this.filterResults(filterFormatted);
          this.filterUpdated.emit(true);
        }
      );

I thought that the inner stream this.filterForm.valueChanges would not work because it is dependent on the the event this.filters.categoriesReady which is fired only once (indeed the console.log print out once) and so I thought that it was not always listening as I would have liked. Instead the code in the subscribe function is executed each time there are changes applied to the filters. Can someone explain it to me?

3
  • By doing switchMap you actually subscribed to observable and you will be notified each time. It is not like it will unsubscribe after first emit. If you want to get only the latest value from particular observable try using withLatestFrom. Commented Aug 2, 2019 at 17:05
  • I would recommand reading switchMap documentation, because it might not be doing what you want it to do.
    – Morphyish
    Commented Aug 2, 2019 at 17:10
  • switchMap works like this: let's say you're only interested in the latest JS trends. And each time a new JS framework goes out, you want to forget about all the previous ones and become an expert on the newest trendy framework. So you subscribe the the "new JS framework is out" observable to be notified when a new framework goes out. And every time one goes out, you unsubscribe from the blog about the old framework, and subscribe to the blog about the newest one. So, in your case, every time categoriesReady emits, you subscribe to all the changes emitted by your form.
    – JB Nizet
    Commented Aug 2, 2019 at 17:12

1 Answer 1

1

switchMap switches into a new inner observable after the outter observable emits, so the outter only needs to emit once. The behavior of switchMap though is that it cancels and resubscribes to the inner observable everytime the outter observable emits.

TBH, in this case, you seem to just be using the outter observable to guarantee the inner observable isn't subscribed until categoriesReady observable emits. I'm not sure what the reasoning behind that is, when you could't just subscribed to both independently since they don't seem to be reliant upon eachother.., nor am I sure why _formatFilters returns an observable.

but hope that clears up the switchMap behavior

4
  • You get the point bryan, I use the outter observable to notify that the categories were successfully fetched from remote and to be able to create and register the reactive form controls. I can subuscribe to this.filterForm.valueChanges independently and still work but I wanted to prevent valueChanges from emitting when I was registering the controls of the categories.
    – berno
    Commented Aug 3, 2019 at 19:01
  • I'd probably use combineLatest or withLatestFrom to accomplish that and still maintain separate streams
    – bryan60
    Commented Aug 3, 2019 at 19:03
  • Ok I will try it out and I understand what you mean when you said me "switchMap switches into a new inner observable after the outter observable emits, so the outter only needs to emit once" but the last switchMap is not the .valueChanges but the stream of this._formatFilters(filtersRaw) for this reason I didn't think that the .valueChanges was still "listening". Thanks in advance, I hope I explained myself
    – berno
    Commented Aug 3, 2019 at 19:13
  • all of the inner observables are still listening. they just cancel and resubscribe after a new value emits
    – bryan60
    Commented Aug 3, 2019 at 19:22

Not the answer you're looking for? Browse other questions tagged or ask your own question.