Here is a simplified version of my code - which I have verified is plagued by the same issue (I have omitted the imports and @Component declarations for simplicity, but they are in my code).
export class Tester implements OnChanges {
@Input() id: string;
public id$ = new EventEmitter<string>();
public boundToIdUpdates$ = this.id$.pipe(
tap((id) => console.log('boundToIdUpdate$ was subscribed to for id', id)),
switchMap((id) => of(id + ' binding'))
);
ngOnChanges(changes: SimpleChanges): void {
// Set `id$` var to emit update on every change of the input.
if (!!changes.id) {
const {currentValue, previousValue} = changes.id;
if (!!currentValue && currentValue !== previousValue) {
this.id$.emit(currentValue);
console.log('emitting', currentValue);
}
}
}
}
<div class="card">
<div class="card-header">Case {{ id }}</div>
<div class="card-block">
<div class="card-title">
@if (boundToIdUpdates$ | async; as boundId) {
Bound ID: {{ boundId }}
} @else {
No Bound ID Available
}
</div>
</div>
</div>
Every time, without fail, I see the following:
emitting id
printed to the consoleNo Bound ID Available
displayed in my componentconsole.log
line about the subscription never prints{{id$ | async}}
, it also never displays anythingAt this point I'm certain I'm missing something obvious, have found a deeper issue with Angular/RXJS, or am taking crazy pills. Help?
RxJs could be tricky. Here is what happens:
This line:
public boundToIdUpdates$ = this.id$.pipe(
tap((id) => console.log('boundToIdUpdate$ was subscribed to for id', id)),
switchMap((id) => of(id + ' binding'))
);
returns AnonymousSubject
. Same as a regular Subject
it does not return last value to the new subscription. First ngOnChanges
call happens before the view is actually initialised, which means that this.id$.emit(currentValue)
emits new value before boundToIdUpdates$ | async
subscription is created. So async pipe is actually missed the emission and will never get a value before the new one comes.
I am not sure why do you want to use EventEmitter
as a source observable. A simple:
public id$ = new BehaviorSubject<string>('');
should help.