Angular 2 @ViewChild annotation returns undefined
The issue as previously mentioned is the ngIf
which is causing the view to be undefined. The answer is to use ViewChildren
instead of ViewChild
. I had similar issue where I didn't want a grid to be shown until all the reference data had been loaded.
html:
<section class="well" *ngIf="LookupData != null">
<h4 class="ra-well-title">Results</h4>
<kendo-grid #searchGrid> </kendo-grid>
</section>
Component Code
import { Component, ViewChildren, OnInit, AfterViewInit, QueryList } from '@angular/core';
import { GridComponent } from '@progress/kendo-angular-grid';
export class SearchComponent implements OnInit, AfterViewInit
{
//other code emitted for clarity
@ViewChildren("searchGrid")
public Grids: QueryList<GridComponent>
private SearchGrid: GridComponent
public ngAfterViewInit(): void
{
this.Grids.changes.subscribe((comps: QueryList <GridComponent>) =>
{
this.SearchGrid = comps.first;
});
}
}
Here we are using ViewChildren
on which you can listen for changes. In this case any children with the reference #searchGrid
. Hope this helps.
I had a similar issue and thought I'd post in case someone else made the same mistake. First, one thing to consider is AfterViewInit
; you need to wait for the view to be initialized before you can access your @ViewChild
. However, my @ViewChild
was still returning null. The problem was my *ngIf
. The *ngIf
directive was killing my controls component so I couldn't reference it.
import { Component, ViewChild, OnInit, AfterViewInit } from 'angular2/core';
import { ControlsComponent } from './controls/controls.component';
import { SlideshowComponent } from './slideshow/slideshow.component';
@Component({
selector: 'app',
template: `
<controls *ngIf="controlsOn"></controls>
<slideshow (mousemove)="onMouseMove()"></slideshow>
`,
directives: [SlideshowComponent, ControlsComponent],
})
export class AppComponent {
@ViewChild(ControlsComponent) controls: ControlsComponent;
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
}
onMouseMove(event) {
this.controls.show();
// throws an error because controls is null
}
}
Hope that helps.
EDIT
As mentioned by @Ashg below, a solution is to use @ViewChildren
instead of @ViewChild
.
You could use a setter for @ViewChild()
@ViewChild(FilterTiles) set ft(tiles: FilterTiles) {
console.log(tiles);
};
If you have an ngIf wrapper, the setter will be called with undefined, and then again with a reference once ngIf allows it to render.
My issue was something else though. I had not included the module containing my "FilterTiles" in my app.modules. The template didn't throw an error but the reference was always undefined.