Search code examples
angularrxjsrxjs-observables

How do I use the result of the outer observer in the inner observer of switchMapTo?


I am using switchMapTo to create an inner stream that is triggered by an outer observer.

What I'd like to do (but can't)

// a change in value of categoryId triggers the inner observer to reinitialize
this.category$ = this.categoryId$.pipe(
  switchMapTo((newCategoryId) => 
    // inner stream is reinitialized using result from outer stream
    this.categoriesQuery.selectEntity(newCategoryId)
  )
)

...because this is how switchMapTo actually works

.switchMapTo doesn't actually return the result from the outer observer to the inner observer. As far as I can tell, the inner stream is initialized just once and then it is triggered by each new emission from the outer observer

How .switchMapTo actually works:

this.category$ = this.categoryId$.pipe(
  switchMapTo(
    this.categoriesQuery.selectEntity(newCategoryId) // <= where does newCategoryId come from now?
  )
)

And the inner observer is only initialized once

Unfortunately this doesn't work either:

this.category$ = this.categoryId$.pipe(
  tap((newValue) => {
     this.currentCategoryId = newValue
  }),
  switchMapTo(() =>{
    this.categoriesQuery.selectEntity(this.currentCategoryId)
  }
  )
)

Because the inner observer is only initialized once (not at every emission from the outer observer) and so the value of this.currentCategoryId is hard-coded in the first time it's evaluated.

Is it possible to do what I want to do?

I'm pretty stuck. I'd like to have the effect of switchMapTo i.e. the outer observer triggers the emission of a new inner stream. But it needs to be a new inner stream and not just the repetition of the original one. Is this possible?


Solution

  • use switchMap, not switchMapTo...

    this.category$ = this.categoryId$.pipe(
      switchMap((newCategoryId) => 
        // inner stream is reinitialized using result from outer stream
        this.categoriesQuery.selectEntity(newCategoryId)
      )
    )
    

    switchMapTo is essentially a shorthand for a switchMap that switches into a static observable that doesn't care about the outer observable, not a dynamic one that relies on it, that's what switchMap is for.

    Similar logic applies to all operators with a To variant such as map and mapTo ... you usually want the plain one, the To variants are more special case.