我正在努力学习Angular 2 .
我想使用 @ViewChild Annotation从父组件访问子组件 .
这里有一些代码行:
在 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 标签中(实际上我能够看到 Headers ) .
注意: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
写入控制台日志时,我得到了 undefined
,当我尝试在"tiles"数组中推送一些内容时,我当然会得到一个异常:'no property tiles for 368579 ' .
还有一件事:FilterTiles组件似乎正确加载,因为我能够看到它的html模板 .
有什么建议吗?谢谢
13 回答
我有一个类似的问题,并认为我发布以防其他人犯了同样的错误 . 首先,要考虑的一件事是
AfterViewInit
;您需要等待视图初始化才能访问@ViewChild
. 但是,我的@ViewChild
仍然返回null . 问题是我的*ngIf
.*ngIf
指令正在杀死我的控件组件,所以我无法引用它 .希望有所帮助 .
EDIT
如下面@Ashg所述,解决方案是使用
@ViewChildren
而不是@ViewChild
.In my case, I knew the child component would always be present, but wanted to alter the state prior to the child initializing to save work.
我选择测试孩子直到它出现并立即进行更改,这为子组件节省了一个更改周期 .
警告,您可以添加最大尝试次数或向
setTimeout
添加几毫秒的延迟 .setTimeout
有效地将函数抛出到挂起操作列表的底部 .它必须工作 .
但正如 Günter Zöchbauer 所说,模板中一定存在其他一些问题 . 我创造了有点Relevant-Plunkr-Answer . 请检查浏览器的控制台 .
boot.ts
filterTiles.ts
它就像一个魅力 . 请仔细检查您的标签和参考 .
谢谢...
这适用于我,请参阅下面的示例 .
我的解决方案是将ngIf从子组件外部移动到包含整个html部分的div的子组件内部 . 这样它仍然需要隐藏,但能够加载组件,我可以在父级中引用它 .
我有一个类似的问题,
ViewChild
在一个switch
子句内部,在它被引用之前没有加载viewChild元素 . 我以一种半hacky的方式解决了它,但将ViewChild
引用包含在立即执行的_368610中(即0ms)您可以使用
@ViewChild()
的setter如果你有一个ngIf包装器,将使用undefined调用setter,然后在ngIf允许它渲染时再使用引用 .
我的问题是其他问题 . 我没有在我的app.modules中包含包含我的“FilterTiles”的模块 . 模板没有抛出错误,但引用始终未定义 .
我的解决方法是使用[style.display] =“getControlsOnStyleDisplay()”而不是* ngIf =“controlsOn” . 块在那里,但不显示 .
我的解决方案是用[hidden]替换* ngIf . 下行是代码DOM中存在的所有子组件 . 但是按照我的要求工作 .
我修复它只是在设置可见组件后添加SetTimeout
我的HTML:
我的组件JS
在我的例子中,我有一个使用ViewChild的输入变量setter,而ViewChild在* ngIf指令中,所以setter试图在* ngIf渲染之前访问它(它会在没有* ngIf的情况下正常工作,但是如果* ngIf =“true”总是设置为true,则不起作用 .
为了解决这个问题,我使用了Rxjs来确保对ViewChild的任何引用都等到视图启动 . 首先,创建一个在查看init之后完成的Subject .
然后,创建一个在主题完成后执行lambda的函数 .
最后,确保对ViewChild的引用使用此函数 .
这对我有用 .
例如,名为“my-component”的组件使用* ngIf =“showMe”显示,如下所示:
因此,当组件初始化时,组件尚未显示,直到“showMe”为真 . 因此,我的@ViewChild引用都是未定义的 .
这是我使用@ViewChildren和它返回的QueryList的地方 . 见angular article on QueryList and a @ViewChildren usage demo .
您可以使用@ViewChildren返回的QueryList,并使用rxjs订阅对引用项的任何更改,如下所示 . @ViewChid没有这种能力 .
希望这能帮助别人节省一些时间和挫折感 .
前面提到的问题是导致视图的ngIf不确定 . 答案是使用ViewChildren而不是ViewChild . 我有类似的问题,我不希望在加载所有参考数据之前显示网格 .
html:
Component Code
在这里,我们使用ViewChildren来监听更改 . 在这种情况下,任何带有#searchGrid引用的子节点 . 希望这可以帮助 .