Angular 2 @ViewChild annotation returns undefined Angular 2 @ViewChild annotation returns undefined angular angular

Angular 2 @ViewChild annotation returns undefined


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.


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.


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.