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.
