public lotId$ = new Subject<number>();
@Input() public set lotId(value: number) {
this.lotId$.next(value);
};
public results$ = this.lotId$.asObservable().pipe(
skipWhile(lotId => !lotId),
switchMap(lotId => this.logicService.getMappedTakeOffTasksForLot(lotId)),
tap(console.log)
);
In the code above, results$
does not emit every time lotId$
emits. Anyone know why? the code runs over results$
once when the component is created and then never again.
EDIT: The source emits 58.
EDIT: It works when I change from Subject
to BehaviorSubject
. Why? I wish I tried that sooner.
CodePudding user response:
results$ does not emit every time lotId$ emits.
Subscriptions to results$
that occur before lotId$
emits, will receive those values. To put it another way, late subscribers don't receive prior values (by "late subscriber" I mean subscription after some emissions have occurred).
Assuming you are using async
pipe in your template, the subscription of results$
doesn't happen until after the view has been initialized, but the @Input() setters are called before that happens.
You will find that if you subscribe in the constructor (just for experimentation), the derived results$
will in fact emit the initial values.
So, it should be clear why changing to
If a component has an optional @Input()
, I use BehaviorSubject
since a default value is needed. If the input is required I use ReplaySubject(1)
, so my logic is not executed unless the consumer provides the input.
Here's a little StackBlitz where you can see the order of the Angular lifecycle hooks and when the subscriptions occur.