Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Identify whether a Angular2 component is completely loaded ( including ViewChilds ) when there is ngIf in template

Is it possible to Identify whether a Angular2 component (here AppComponent) is completely loaded ( including ViewChilds ) when there ngIf in template which conditionally loads the child.

Reference: Angular 2 @ViewChild annotation returns undefined This example is taken from the above reference. Thanks to kenecaswell

import {Component, ViewChild, OnInit, AfterViewInit} from 'angular2/core';
import {ControlsComponent} from './child-component-1';
import {SlideshowComponent} from './slideshow/slideshow.component';

@Component({
    selector: 'app',
    template:  `
        <div *ngIf="controlsOn">
            <controls ></controls>
            <slideshow></slideshow>
        </div>
    `,
    directives: [SlideshowComponent, ControlsComponent]
})

export class AppComponent {
    @ViewChild(ControlsComponent) controls:ControlsComponent;   
    @ViewChild(SlideshowComponent) slide:SlideshowComponent;

    controlsOn:boolean = false;

    ngOnInit() {
        console.log('on init', this.controls);
        // this returns undefined
    }

    ngAfterViewInit() {
        console.log('on after view init', this.controls);
        // this returns null
    }

}

The ngOnInit && ngAfterViewInit are fired before the the child components are loaded because of the ngIf condition

I need identify when SlideshowComponent & ControlsComponent are loaded and perform an action based on that.

I have a hacky solution which is not suitable when there are multiple ViewChilds (Which are of different type) - Using an event emitter to inform when the child is loaded.

I'm posting this question since there were no proper solution after hours of research.

like image 589
tymspy Avatar asked Jul 12 '16 10:07

tymspy


2 Answers

PLUNKER

Try ViewChildren instead of ViewChild, which provides a changes Observable, we can use as a hook.

To track all the ViewChildren, you can merge their changes Observables into one and subscribe to it, then you get single point of action, like this

  @ViewChildren(ChildCmp) children: QueryList<ChildCmp>;
  @ViewChildren(AnotherChildCmp) anotherChildren: QueryList<ChildCmp>;

  childrenDetector: Observable<any>; // merged observable to detect changes in both queries

  ngAfterViewInit(){
    this.childrenDetector = Observable.merge(this.children.changes, this.anotherChildren.changes)

    this.childrenDetector.subscribe(() => {

      // here you can even check the count of view children, that you queried
      // eg:  if(this.children.length === 1 && this.anotherChildren.length === 1) { bothInitialized(); }
      // or something like that

      alert('you just initialized a children');
    });
  }
}
like image 154
Ankit Singh Avatar answered Oct 07 '22 21:10

Ankit Singh


You can wrap stuff in *ngIf so that html won't show anything untill ngOnInit finished all.

<div *ngIf="loaded">
    /* all codes go here */
<div>

OnInit(){
    foo();
    bar(()=>{
        this.loaded = true;
    });
}
like image 29
Peter Huang Avatar answered Oct 07 '22 22:10

Peter Huang