Reputation: 3030
I have what I think is a very basic setup. Component A renders component B.
Component A exposes a Subject
and in it's template passes the subject (using async pipe) to one of component B's properties:
@Component({
template: "
<div><app-comp-b [input]='s | async'></app-comp-b></div>
"
})
class CompA {
s: BehaviorSubject<string> = new BehaviorSubject<string>('');
change(newS: string) { this.s.next(newS); }
}
class CompB {
@Input() input: string;
}
For some reason, B only gets the initial value of s
. Subsequent calls to change
(which create a new value in s
) have no effect on B. That is, the value of input
does not change (for example, if I render it in B's template).
If I subscribe manually to s
, e.g. s.subscribe(ss => console.log(ss));
I can see the values as they come in get printed in the console.
More than that, if I use pipe
and tap
to print values, nothing happens until I manually subscribe. This hints to me that the Comp B does not subscribe to s
.
What am I doing wrong? (I am using angular 4.4.7)
Upvotes: 0
Views: 301
Reputation: 3030
Thanks to @SiddAjmera example I found the problem.
In my code, the change()
function is not called by a button, instead it's triggered by an event fired from another component. When I use a button it starts working!
So I added a call to detectChanges
and it is now working also from the event.
I am new to Angular but if I understand correctly, angular does not detect the change because the reference to the Subject s
does not change. Instead it is updated with a new value. So we must force detect changes.
To add detectChanges
I injected the change detector in the c'tor of comp A and called detect changes in change
:
class CompA {
constructor(private cd: ChangeDetectorRef) {}
s: BehaviorSubject<string> = new BehaviorSubject<string>('');
change(newS: string) {
this.s.next(newS);
this.cd.detectChanges();
}
}
Upvotes: 1