My goal was to avoid any hacky methods that assume something (e.g. setTimeout) and I ended up implementing the accepted solution with a bit of RxJS flavour on top:
private ngUnsubscribe = new Subject();
private tabSetInitialized = new Subject();
public tabSet: TabsetComponent;
@ViewChild('tabSet') set setTabSet(tabset: TabsetComponent) {
if (!!tabSet) {
this.tabSet = tabSet;
this.tabSetInitialized.next();
}
}
ngOnInit() {
combineLatest(
this.route.queryParams,
this.tabSetInitialized
).pipe(
takeUntil(this.ngUnsubscribe)
).subscribe(([queryParams, isTabSetInitialized]) => {
let tab = [undefined, 'translate', 'versions'].indexOf(queryParams['view']);
this.tabSet.tabs[tab > -1 ? tab : 0].active = true;
});
}
My scenario: I wanted to fire an action on a @ViewChild
element depending on the router queryParams
. Due to a wrapping *ngIf
being false until the HTTP request returns the data, the initialization of the @ViewChild
element happens with a delay.
How does it work: combineLatest
emits a value for the first time only when each of the provided Observables emit the first value since the moment combineLatest
was subscribed to. My Subject tabSetInitialized
emits a value when the @ViewChild
element is being set. Therewith, I delay the execution of the code under subscribe
until the *ngIf
turns positive and the @ViewChild
gets initialized.
Of course don't forget to unsubscribe on ngOnDestroy, I do it using the ngUnsubscribe
Subject:
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}