Angular 2 @ViewChild注解返回undefined

我正在学习Angular 2。

我想使用@ViewChild注解从父组件访问一个子组件。

这里有几行代码:

BodyContent.ts中我有:

import {ViewChild, Component, Injectable} from 'angular2/core'; import {FilterTiles} from '../Components/FilterTiles/FilterTiles'; @Component({ selector: 'ico-body-content' , templateUrl: 'App/Pages/Filters/BodyContent/BodyContent.html' , directives: [FilterTiles] }) export class BodyContent { @ViewChild(FilterTiles) ft:FilterTiles; public onClickSidebar(clickedElement: string) { console.log(this.ft); var startingFilter = { title: 'cognomi', values: [ 'griffin' , 'simpson' ]} this.ft.tiles.push(startingFilter); } } 

而在FilterTiles.ts中

  import {Component} from 'angular2/core'; @Component({ selector: 'ico-filter-tiles' ,templateUrl: 'App/Pages/Filters/Components/FilterTiles/FilterTiles.html' }) export class FilterTiles { public tiles = []; public constructor(){}; } 

最后在这里的模板(如评论中所build议的):

BodyContent.html

 <div (click)="onClickSidebar()" class="row" style="height:200px; background-color:red;"> <ico-filter-tiles></ico-filter-tiles> </div> 

FilterTiles.html

 <h1>Tiles loaded</h1> <div *ngFor="#tile of tiles" class="col-md-4"> ... stuff ... </div> 

FilterTiles.html模板被正确地加载到ico-filter-tiles标记(的确能看到标题)。

注意:BodyContent类使用DynamicComponetLoader注入到另一个模板(Body)中:dcl.loadAsRoot(BodyContent,'#ico-bodyContent',injector):

 import {ViewChild, Component, DynamicComponentLoader, Injector} from 'angular2/core'; import {Body} from '../../Layout/Dashboard/Body/Body'; import {BodyContent} from './BodyContent/BodyContent'; @Component({ selector: 'filters' , templateUrl: 'App/Pages/Filters/Filters.html' , directives: [Body, Sidebar, Navbar] }) export class Filters { constructor(dcl: DynamicComponentLoader, injector: Injector) { dcl.loadAsRoot(BodyContent, '#ico-bodyContent', injector); dcl.loadAsRoot(SidebarContent, '#ico-sidebarContent', injector); } } 

问题是,当我尝试将ft写入控制台日志时,出现“未定义” ,当然,当我尝试在“tiles”数组内部推送某些内容(没有属性tile为“undefined”)时,我会遇到exception。

还有一件事:FilterTiles组件似乎正确加载,因为我能够看到它的HTML模板。

任何build议? 谢谢

我有类似的问题,并认为我会张贴,以防其他人犯了同样的错误。 首先,要考虑的一件事是AfterViewInit; 你需要等待视图被初始化,然后才能访问你的@ViewChild。 不过,我的@ViewChild仍然返回null。 问题是我的* ngIf。 * ngIf指令正在杀死我的控件组件,所以我不能引用它。

 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 } } 

希望有所帮助。

前面提到的问题是ngIf导致视图未定义。 答案是使用ViewChildren而不是ViewChild。 我有类似的问题,我不希望一个网格显示,直到所有的参考数据已被加载。

HTML:

  <section class="well" *ngIf="LookupData != null"> <h4 class="ra-well-title">Results</h4> <kendo-grid #searchGrid> </kendo-grid> </section> 

组件代码

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

在这里,我们使用ViewChildren,您可以在其中侦听更改。 在这种情况下,任何孩子参考#searchGrid。 希望这可以帮助。

这对我有效。

例如,我的名为“my-component”的组件使用* ngIf =“showMe”显示,如下所示:

 <my-component [showMe]="showMe" *ngIf="showMe"></my-component> 

所以,当组件被初始化时,组件还没有被显示,直到“showMe”为真。 因此,我的@ViewChild引用都是未定义的。

这是我使用@ViewChildren和它返回的QueryList。 查看有关QueryList和@ViewChildren使用演示的文章 。

您可以使用@ViewChildren返回的QueryList,并使用rxjs订阅引用项目的任何更改,如下所示。 @ViewChid没有这个能力。

 import { Component, ViewChildren, ElementRef, OnChanges, QueryList, Input } from '@angular/core'; import 'rxjs/Rx'; @Component({ selector: 'my-component', templateUrl: './my-component.component.html', styleUrls: ['./my-component.component.css'] }) export class MyComponent implements OnChanges { @ViewChildren('ref') ref: QueryList<any>; // this reference is just pointing to a template reference variable in the component html file (ie <div #ref></div> ) @Input() showMe; // this is passed into my component from the parent as a ngOnChanges () { // ngOnChanges is a component LifeCycle Hook that should run the following code when there is a change to the components view (like when the child elements appear in the DOM for example) if(showMe) // this if statement checks to see if the component has appeared becuase ngOnChanges may fire for other reasons this.ref.changes.subscribe( // subscribe to any changes to the ref which should change from undefined to an actual value once showMe is switched to true (which triggers *ngIf to show the component) (result) => { // console.log(result.first['_results'][0].nativeElement); console.log(result.first.nativeElement); // Do Stuff with referenced element here... } ); // end subscribe } // end if } // end onChanges } // end Class 

希望这有助于节省一些时间和挫折。

我的解决方法是使用[style.display] =“getControlsOnStyleDisplay()”,而不是* ngIf =“controlsOn”。 该块在那里,但不显示。

 @Component({ selector: 'app', template: ` <controls [style.display]="getControlsOnStyleDisplay()"></controls> ... export class AppComponent { @ViewChild(ControlsComponent) controls:ControlsComponent; controlsOn:boolean = false; getControlsOnStyleDisplay() { if(this.controlsOn) { return "block"; } else { return "none"; } } .... 

它必须工作。

但是正如GünterZöchbauer所说的那样,模板中一定还有其他的问题。 我创造了一个相关的普朗克答案 。 请检查浏览器的控制台。

boot.ts

 @Component({ selector: 'my-app' , template: `<div> <h1> BodyContent </h1></div> <filter></filter> <button (click)="onClickSidebar()">Click Me</button> ` , directives: [FilterTiles] }) export class BodyContent { @ViewChild(FilterTiles) ft:FilterTiles; public onClickSidebar() { console.log(this.ft); this.ft.tiles.push("entered"); } } 

filterTiles.ts

 @Component({ selector: 'filter', template: '<div> <h4>Filter tiles </h4></div>' }) export class FilterTiles { public tiles = []; public constructor(){}; } 

它像一个魅力。 请仔细检查您的标签和参考。

谢谢…

我的解决scheme是将ngIf从子组件的外部移动到包含整个html部分的div上的子组件的内部。 这样,当它需要的时候它仍然隐藏起来,但是能够加载组件,我可以在父项中引用它。

这适用于我,看下面的例子。

 import {Component, ViewChild, ElementRef} from 'angular2/core'; @Component({ selector: 'app', template: ` <a (click)="toggle($event)">Toggle</a> <div *ngIf="visible"> <input #control name="value" [(ngModel)]="value" type="text" /> </div> `, }) export class AppComponent { private elementRef: ElementRef; @ViewChild('control') set controlElRef(elementRef: ElementRef) { this.elementRef = elementRef; } visible:boolean; toggle($event: Event) { this.visible = !this.visible; if(this.visible) { setTimeout(() => { this.elementRef.nativeElement.focus(); }); } } } 

这将是容易的。 试试这个,如果你不想渲染元素,仍然通过没有任何错误。 只要放置一个if条件来检查undefined:

  @ViewChild(ControlsComponent) controls:ControlsComponent; ..... if(controls){ controls.yourChildFunction(); }