I'm trying a very simple example of calling childMethod inside the child component from the parent component via @ViewChild() decorator. Unfortunately, the ViewChild variable is always undefined.
Child Component
import {Component, Input, Output, EventEmitter} from '@angular/core';
import {Character} from "../models/character";
@Component({
selector: 'my-character',
templateUrl: 'app/components/my.character.component.html'
})
export class MyCharacter {
@Output() changed: EventEmitter<any> = new EventEmitter();
@Input() character: Character;
selectedCharacter: Character;
select(selectedCharacter: Character) {
this.selectedCharacter = selectedCharacter;
this.changed.emit(selectedCharacter);
};
childMethod() {
console.log('This method is called from the parent component via ViewChild');
};
}
Parent Component
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { Character } from '../models/character';
import { MyCharacter } from "../components/my.character.component";
@Component({
selector: 'character-list',
templateUrl: 'app/components/character.list.component.html',
directives: [ MyCharacter ]
})
export class CharacterList implements AfterViewInit{
selectedCharacter: Character;
@ViewChild(MyCharacter) myChar:MyCharacter;
ngOnInit() {
console.log('on init');
};
ngAfterViewInit() {
console.log('after init');
};
characters = [
new Character(1, 'Han Solo'),
new Character(2, 'Luke Skywalker'),
new Character(3, 'BB-8'),
new Character(4, 'Rey')
];
select(selectedCharacter: Character) {
this.selectedCharacter = selectedCharacter;
this.myChar.childMethod();
}
changed (event: any) {
console.log('Hello! There is a change in the item.');
}
}
parent component html
<h2>Characters</h2>
<ul>
<li *ngFor="let character of characters" (click)="select(character)">
{{character.name}}
</li>
</ul>
<my-character *ngIf="selectedCharacter" [character]="selectedCharacter" (changed)="changed($event)"></my-character>
Error I am getting when I invoke click method
core.umd.js:3462 EXCEPTION: Error in app/components/character.list.component.html:3:45 caused by: Cannot read property 'childMethod' of undefinedErrorHandler.handleError @ core.umd.js:3462next @ core.umd.js:6924schedulerFn @ core.umd.js:6172SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238SafeSubscriber.next @ Subscriber.ts:190Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95Subject.next @ Subject.ts:61EventEmitter.emit @ core.umd.js:6164onError @ core.umd.js:6388onHandleError @ core.umd.js:6263ZoneDelegate.handleError @ zone.js:207Zone.runGuarded @ zone.js:113NgZoneImpl.runInnerGuarded @ core.umd.js:6271NgZone.runGuarded @ core.umd.js:6504outsideHandler @ platform-browser.umd.js:1990ZoneDelegate.invokeTask @ zone.js:236Zone.runTask @ zone.js:136ZoneTask.invoke @ zone.js:304
core.umd.js:3464 ORIGINAL EXCEPTION: Cannot read property 'childMethod' of undefinedErrorHandler.handleError @ core.umd.js:3464next @ core.umd.js:6924schedulerFn @ core.umd.js:6172SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238SafeSubscriber.next @ Subscriber.ts:190Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95Subject.next @ Subject.ts:61EventEmitter.emit @ core.umd.js:6164onError @ core.umd.js:6388onHandleError @ core.umd.js:6263ZoneDelegate.handleError @ zone.js:207Zone.runGuarded @ zone.js:113NgZoneImpl.runInnerGuarded @ core.umd.js:6271NgZone.runGuarded @ core.umd.js:6504outsideHandler @ platform-browser.umd.js:1990ZoneDelegate.invokeTask @ zone.js:236Zone.runTask @ zone.js:136ZoneTask.invoke @ zone.js:304
core.umd.js:3467 ORIGINAL STACKTRACE:ErrorHandler.handleError @ core.umd.js:3467next @ core.umd.js:6924schedulerFn @ core.umd.js:6172SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238SafeSubscriber.next @ Subscriber.ts:190Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95Subject.next @ Subject.ts:61EventEmitter.emit @ core.umd.js:6164onError @ core.umd.js:6388onHandleError @ core.umd.js:6263ZoneDelegate.handleError @ zone.js:207Zone.runGuarded @ zone.js:113NgZoneImpl.runInnerGuarded @ core.umd.js:6271NgZone.runGuarded @ core.umd.js:6504outsideHandler @ platform-browser.umd.js:1990ZoneDelegate.invokeTask @ zone.js:236Zone.runTask @ zone.js:136ZoneTask.invoke @ zone.js:304
core.umd.js:3468 TypeError: Cannot read property 'childMethod' of undefined
at CharacterList.select (character.list.component.ts:31)
at DebugAppView._View_CharacterList1._handle_click_0_0 (CharacterList.ngfactory.js:157)
at eval (core.umd.js:9698)
at eval (platform-browser.umd.js:1877)
at eval (platform-browser.umd.js:1990)
at ZoneDelegate.invoke (zone.js:203)
at Object.onInvoke (core.umd.js:6242)
at ZoneDelegate.invoke (zone.js:202)
at Zone.runGuarded (zone.js:110)
at NgZoneImpl.runInnerGuarded (core.umd.js:6271)ErrorHandler.handleError @ core.umd.js:3468next @ core.umd.js:6924schedulerFn @ core.umd.js:6172SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238SafeSubscriber.next @ Subscriber.ts:190Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95Subject.next @ Subject.ts:61EventEmitter.emit @ core.umd.js:6164onError @ core.umd.js:6388onHandleError @ core.umd.js:6263ZoneDelegate.handleError @ zone.js:207Zone.runGuarded @ zone.js:113NgZoneImpl.runInnerGuarded @ core.umd.js:6271NgZone.runGuarded @ core.umd.js:6504outsideHandler @ platform-browser.umd.js:1990ZoneDelegate.invokeTask @ zone.js:236Zone.runTask @ zone.js:136ZoneTask.invoke @ zone.js:304
core.umd.js:3471 ERROR CONTEXT:ErrorHandler.handleError @ core.umd.js:3471next @ core.umd.js:6924schedulerFn @ core.umd.js:6172SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238SafeSubscriber.next @ Subscriber.ts:190Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95Subject.next @ Subject.ts:61EventEmitter.emit @ core.umd.js:6164onError @ core.umd.js:6388onHandleError @ core.umd.js:6263ZoneDelegate.handleError @ zone.js:207Zone.runGuarded @ zone.js:113NgZoneImpl.runInnerGuarded @ core.umd.js:6271NgZone.runGuarded @ core.umd.js:6504outsideHandler @ platform-browser.umd.js:1990ZoneDelegate.invokeTask @ zone.js:236Zone.runTask @ zone.js:136ZoneTask.invoke @ zone.js:304
core.umd.js:3472 DebugContext {_view: _View_CharacterList1, _nodeIndex: 0, _tplRow: 3, _tplCol: 45}ErrorHandler.handleError @ core.umd.js:3472next @ core.umd.js:6924schedulerFn @ core.umd.js:6172SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238SafeSubscriber.next @ Subscriber.ts:190Subscriber._next @ Subscriber.ts:135Subscriber.next @ Subscriber.ts:95Subject.next @ Subject.ts:61EventEmitter.emit @ core.umd.js:6164onError @ core.umd.js:6388onHandleError @ core.umd.js:6263ZoneDelegate.handleError @ zone.js:207Zone.runGuarded @ zone.js:113NgZoneImpl.runInnerGuarded @ core.umd.js:6271NgZone.runGuarded @ core.umd.js:6504outsideHandler @ platform-browser.umd.js:1990ZoneDelegate.invokeTask @ zone.js:236Zone.runTask @ zone.js:136ZoneTask.invoke @ zone.js:304
zone.js:140 Uncaught Error: Error in app/components/character.list.component.html:3:45 caused by: Cannot read property 'childMethod' of undefined
Any clarification would be helpful.
This is the culprit:
*ngIf="selectedCharacter"
That ngIf
will prevent the ViewChild
from being instantiated before it's too late. You can move it to inside MyCharacter
's template to have the ViewChild
reference in parent component without changing any behaviour of your app.