The OP seems to think it doesn't suit his needs, or is not elegant, but it seems that Vale Steve's answer is the most logical approach here.
In my case I needed to wait for 2 child components to initialize, which control left and right panels in my app. I have both child components declaring their initialization to a shared service:
constructor(
public _navigate: RouteNavigationService // service shared between all child components and parent
){}
ngOnInit() {
this._navigate.setChildInit(this.panel);
}
Shared service (RouteNavigationService):
private _leftChildInit = new Subject();
private _rightChildInit = new Subject();
leftChildInit$ = this._leftChildInit.asObservable();
rightChildInit$ = this._rightChildInit.asObservable();
setChildInit(panel){
switch(panel){
case 'leftPanel':
console.log('left panel initialized!');
this._leftChildInit.next(true);
break;
case 'rightPanel':
console.log('right panel initialized!');
this._rightChildInit.next(true);
break;
}
}
Then in my parent component I use the zip method to combine multiple Observables together (You could add additional child components here as well) and wait for them all to finish:
childInitSub: Subscription;
constructor(
public _navigate: RouteNavigationService
) {
this.childInitSub = Observable.zip( // WAIT FOR BOTH LEFT & RIGHT PANELS' ngOnInit() TO FIRE
this._navigate.leftChildInit$,
this._navigate.rightChildInit$).subscribe(data =>
// Both child components have initialized... let's go!
);
}
The OP states in a comment
"I don't like this, since everytime I add a new component I need to
wait for an additional onInit event and have to implement it"
But realistically all you'd have to do is make another Subject
in your service for the new child component ngOnInit, and add an extra line in the parent component zip method.
Note that the accepted answer here, using ngAfterViewInit() isn't doing quite the same thing as above. In my case, using ngAfterViewInit()
was producing an ExpressionChangedAfterItHasBeenCheckedError which is beyond the scope of this question, but serves to demonstrate that this approach is not actually doing the same thing.
In contrast, the above method is quite literally only triggered as a direct result of all your child components' ngOnInit()
events having fired.