Search code examples
angularrxjscombinelatest

How to combine multiple subjects into one and react to every change


I am currently building a stepper component which has multiple step components rendered in its ng-content. In the stepper component i am accessing these components via ContentChildren. Each step component has a Subject which calls .next() when an Input value changes. I am doing this to notify the Parent (StepperComponent), so that i can recreate my model for the view. First i subscribed to each Subject in a foreach loop. I would like to know if it is possible to combine all of my subjects and subscribe to that. Since i dont really care which step changed and just wanna know that some step changed. I have currently tried with merge() and combineLatest() which both did not fire when one of the subjects called .next().

This is how i used merge and combine latest

this.stepsOnChangeSubscription = merge(this.steps.map(s => s.onChanges$))
  .pipe(takeUntil(this.unsubscribe$)).subscribe(_ => this.createStepConfig());

this.stepsOnChangeSubscription = combineLatest(this.steps.map(s => s.onChanges$))
  .pipe(takeUntil(this.unsubscribe$)).subscribe(_ => this.createStepConfig());

Steps are defined as

@ContentChildren(StepComponent) steps: QueryList<StepComponent>;

and $unsubscribe is just to unsubscribe in ngOnDestroy


Solution

  • With combineLatest you need each Subject to emit at least once before you are notified.

    merge is the right choice, but it needs a spreaded array (i.e. ...myArray).

    So, the following should help:

    this.stepsOnChangeSubscription = merge(...this.steps.map(s => s.onChanges$))
      .pipe(takeUntil(this.unsubscribe$)).subscribe(_ => this.createStepConfig());