EDIT 2: This appears to be my general problem, and solution (using setTimeout
so Angular's lifecycle can happen). I'll either close this or post an answer to my own question when I can.
See EDIT for a simpler repro that doesn't involve Subjects/Observables but is essentially the same problem.
I have a parent component that's responsible for fetching data from a service.
export class ParentComponent implements OnInit {
public mySubject: Subject<Foo[]> = new Subject<Foo[]>();
public buttonClicked = false;
private currentValues: Foo[] = null;
constructor(private SomeService myService) { }
this.myService.get().subscribe(values => {
this.mySubject.next(values); // Does NOT work when a child component is hidden, as expected.
this.currentValues = values; // Keep value so we can manually fire later.
});
private buttonClickHandler() {
this.buttonClicked = true;
this.mySubject.next(this.currentValues);
}
}
This data is subscribed to in the HTML by a child component. This component is hidden by default via *ngIf
, and only becomes visible on a button click:
<app-child-component [values]="mySubject.asObservable()" *ngif="buttonClicked" />
In the parent component above you see I'm trying to pass the current available data to the child by invoking next()
when the component is made visible in some way:
this.mySubject.next(this.currentValues);
This does not work when initially un-hiding the component via *ngIf
. If I click the button a second time, which then calls next()
again, then it works as expected. But when Angular is in the current context of un-hiding something, observables aren't getting their data. (This also happens when things are unhidden by other means, but the result is the same: If in the same method, the subject/data passing does not work; the component has to already be visible as of the method call.)
I'm guessing the binding to the observable is not happening until after *ngIf
shows the child component, after the method call resolves. Is there some place I can hook into that I can then pass child data down?
EDIT for clarification: I don't believe this is an issue of Subject
vs. BehaviorSubject
. I'm not having issue passing the data. The issue is that the data-passing (confirmed via console.log()
) is not occurring at all in the first place. It's not that the child component is receiving a null
value. The subscription just isn't firing to the child.
I found I can reproduce this in a simpler fashion too: Trying to select an element in the DOM of *ngIf
HTML reveals undefined if I make *ngIf
's value true within the same Angular method.
<div *ngIf="buttonClicked">
<div id="someElement">Foo</div>
</div>
public someMethod(): void {
this.buttonClicked = true;
const container = document.getElementById('someElement'); // DOES NOT WORK if this.buttonClicked was false at the start of this method!
}