Charles HETIER
Charles HETIER

Reputation: 2068

recursive rxjs switchmap ish

I want a variable states$: an observable stream of objects, with each object containing a member nextState$ of type observable. This property nextState$ sends a unique item corresponding to the next state, and so on...

example:

const states$ = of({ nextState$: createObservableWithNextState$() }).pipe(
switchMap(state => state.nextState$),
switchMap(state => state.nextState$),
switchMap(state => state.nextState$),
switchMap(state => state.nextState$),
...
)

of course it doesn't work, for two reasons at least:

Of course I could create my own observable from scractch but before I would like to known if it would be possible with existing rxjsoperators. Any idea ?...

Upvotes: 1

Views: 311

Answers (2)

ivan_padavan
ivan_padavan

Reputation: 46

Same behaviour as expand but without concurrency can be achieved with

import { from, ObservableInput, OperatorFunction, switchMap } from 'rxjs';

export function switchExpand<T>(
  project: (value: T, index: number) => ObservableInput<T>,
): OperatorFunction<T, T> {
  let index = 0;
  const recursive = (): OperatorFunction<T, T> => switchMap<T, ObservableInput<T>>((value) => from(project(value, index++)).pipe(recursive()));
  return source => source.pipe(
    recursive()
  )
}

Upvotes: 0

Mrk Sef
Mrk Sef

Reputation: 8022

RxJS#expand

Expand should do what you're after pretty simply.
I assume at some point you'll reach a state without a nextState$, but you can change that condition easily.

const states$ = of({ 
  nextState$: createObservableWithNextState$() 
}).pipe(
  expand(state => state.nextState$ != null? state.nextState$ : EMPTY)
);

Expand is closer to mergeMap than switchMap. You can set concurrent to 1 to make it work like concatMap. If you're really after a switchMap-like behaviour, this gets a bit more complicated.

Upvotes: 1

Related Questions