3

我正在尝试一个非常简单的示例,即通过@ViewChild()装饰器从父组件调用子组件内部的childMethod。不幸的是,ViewChild 变量始终未定义。

子组件

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');
    };
}

父组件

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.');
    }
}

父组件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>

调用 click 方法时出现错误

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

任何澄清都会有所帮助。

4

1 回答 1

5

这是罪魁祸首:

*ngIf="selectedCharacter"

ngIf将防止在ViewChild为时已晚之前实例化。您可以将其移动到 insideMyCharacter的模板以ViewChild在父组件中具有引用,而无需更改应用程序的任何行为。

于 2016-09-29T00:12:15.637 回答