Angular 2 @ViewChild 注释返回未定义
我正在尝试学习 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(){};
}
最后这里是模板(如评论中所建议的):
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: dcl.loadAsRoot(BodyContent, '#ico-bodyContent', injectionor)
注入另一个模板(Body)中:
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
写入控制台日志时,我得到了
undefined
,当然,当我尝试将某些内容推送到“tiles”数组中时,我会收到异常:
'no property tiles for "undefined"'
。
还有一件事:
FilterTiles
组件似乎已正确加载,因为我能够看到它的 html 模板。
有什么建议吗?
我遇到了类似的问题,我想发帖以防别人犯同样的错误。首先,需要考虑的一件事是
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
}
}
编辑
正如
@Ashg 在下面
中提到的,解决方案是使用
@ViewChildren
而不是
@ViewChild
。
如前所述,问题是
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
的子项。
您可以为
@ViewChild()
使用 setter。
@ViewChild(FilterTiles) set ft(tiles: FilterTiles) {
console.log(tiles);
};
如果您有一个 ngIf 包装器,setter 将使用未定义的方式调用,然后在 ngIf 允许渲染时再次使用引用调用。
但我的问题是其他问题。我没有在 app.modules 中包含包含“FilterTiles”的模块。模板没有抛出错误,但引用始终未定义。