问题
显示模板中相应元素后获取@ViewChild最优雅的方法是什么?以下是一个例子 . 也Plunker可用 .
模板:
<div id="layout" *ngIf="display">
<div #contentPlaceholder></div>
</div>
零件:
export class AppComponent {
display = false;
@ViewChild('contentPlaceholder', {read: ViewContainerRef}) viewContainerRef;
show() {
this.display = true;
console.log(this.viewContainerRef); // undefined
setTimeout(()=> {
console.log(this.viewContainerRef); // OK
}, 1);
}
}
我有一个默认隐藏其内容的组件 . 当有人调用 show()
方法时,它变得可见 . 但是,在角度2变化检测完成之前,我无法参考 viewContainerRef
. 我通常将所有必需的操作包装到 setTimeout(()=>{},1)
中,如上所示 . 有更正确的方法吗?
我知道 ngAfterViewChecked
有一个选项,但它会导致太多无用的调用 .
8 回答
使用QueryList接受的答案对我不起作用 . 然而,为ViewChild使用setter的工作是什么:
一旦* ngIf变为真,就会调用setter .
克服这个问题的另一种方法是手动运行变化检测器 .
你首先注入
ChangeDetectorRef
:然后在更新控制* ngIf的变量后调用它
上面的答案对我不起作用,因为在我的项目中,ngIf在输入元素上 . 我需要访问nativeElement属性,以便在ngIf为true时关注输入 . ViewContainerRef上似乎没有nativeElement属性 . 这是我做的(关于@ViewChild documentation):
我在聚焦之前使用了setTimeout,因为ViewChild需要一秒钟来分配 . 否则它将是未定义的 .
正如其他人所提到的,最快和最快的解决方案是使用[hidden]而不是* ngIf,这样组件将被创建但不可见,因为你可以访问它,尽管它可能不是最有效的办法 .
这可行,但我不知道你的情况是否方便:
我的目标是避免任何假设某些东西的hacky方法(例如setTimeout),并且我最终在顶部实现了一些RxJS风格的接受解决方案:
My scenario: 我想根据路由器
queryParams
在@ViewChild
元素上触发一个动作 . 由于在HTTP请求返回数据之前包装*ngIf
为假,因此@ViewChild
元素的初始化会发生延迟 .How does it work:
combineLatest
仅在每个提供的Observables从combineLatest
订阅的那一刻起发出第一个值时才首次发出一个值 . 我的主题tabSetInitialized
在设置@ViewChild
元素时发出一个值 . 因此,我延迟了subscribe
下的代码执行,直到*ngIf
变为正,@ViewChild
被初始化 .当然不要忘记取消订阅ngOnDestroy,我使用
ngUnsubscribe
主题:一个简化版本,我在使用Google Maps JS SDK时遇到了类似的问题 .
我的解决方案是将
div
和ViewChild
提取到它自己的子组件中,当在父组件中使用时,可以使用*ngIf
隐藏/显示它 .Before
HomePageComponent
模板HomePageComponent
组件After
MapComponent
模板MapComponent
组件HomePageComponent
模板HomePageComponent
组件这对我有用 . 在将数据绑定到表单后应用一些延迟 .