[英]Angular4 How to know when a ViewChild has been reset
这是main.html
的模板:
<button (click)="displayAndUseMyCustomComp()"></button>
<my-custom-comp *ngIf="isMyCustomCompDisplayed" #myCustomComp="myCustomComp"></my-custom-comp>
和main.component.ts
:
export class MainComponent {
constructor() {}
private isMyCustomCompDisplayed boolean = false
@ViewChild('myCustomComp') myCustomComp: MyCustomComp
displayAndUseMyCustomComp() {
this.isMyCustomCompDisplayed = true
console.log(this.myCustomComp) // prints undefined
setTimeout(() => {
console.log(this.myCustomComp) // prints {object}
})
}
}
发生了什么事情,我将isMyCustomCompDisplayed
设置为true
后,我的模板尚未刷新。 但是,如果我使用setTimeout
, myCustomComp
会更新,我的问题就会消失。 这是中等的hacky,我想知道我正在尝试做什么的正确方法。
displayAndUseMyCustomComp
后它未定义的原因 Angular将ViewChild
查询列表更新为更改检测的一部分。 当Angular运行初始更改检测时, isMyCustomCompDisplayed
为false
,因此隐藏了myCustomComp
。 myCustomComp
设置为undefined
。
单击后,执行displayAndUseMyCustomComp
函数,并将isMyCustomCompDisplayed
设置为true
。 Angular需要更改检测周期来更新myCustomComp
查询列表。 但是,您尝试立即读取该值,因此仍未undefined
。 您需要等待Angular的另一个更改检测周期来更新查询列表。
setTimeout
这就是它的工作setTimeout
如果您尝试在超时内读取myCustomComp
,Angular有机会在更新isMyCustomCompDisplayed
和读取myCustomComp
之间运行更改检测。
当Angular运行MainComponent
更改检测时,它会检测到isMyCustomCompDisplayed
已更新。 所以它会更新ngIf
绑定。 它反过来对此更改做出反应,并使用myCustomComp
创建和嵌入视图,并将其附加到MainComponent
组件:
@Input()
set ngIf(condition: any) {
if (condidition) {
this._viewContainer.createEmbeddedView(this._thenTemplateRef, this._context);
如果您正在寻找同步解决方案,它将在执行displayAndUseMyCustomComp
的下一个更改检测周期中更新视图子查询列表后执行的所有生命周期钩子中可用。 目前这些是ngAfterViewInit
和ngAfterViewChecked
。 由于前者只被调用一次,我们需要使用ngAfterViewChecked
:
ngAfterViewChecked() {
if(this.isMyCustomCompDisplayed) {
console.log(this.myCustomComp) // prints {object}
}
}
displayAndUseMyCustomComp() {
this.isMyCustomCompDisplayed = true
}
@ThinkingMedia
建议的另一个同步解决方案也很好。 您可以使用ViewChildren
而不是ViewChild
并订阅changes
(顺便ViewChild
您没有模板引用):
@ViewChildren(myCustomComp) as: QueryList<myCustomComp>;
ngAfterViewInit() {
this.myCustomComp.changes.subscribe(() => {
console.log(this.myCustomComp.first); // prints {object}
});
}
当Angular将更新查询列表(稍早于ngAfterViewChecked
)时,将在下一个摘要期间触发回调。
如果您正在寻找异步解决方案,请在执行此操作时使用setTimeout
。 Promise.resolve(null).then(()=>{ console.log(this.myCustomComp) })
(microtask)解决方案将无法工作,因为它将在当前堆栈之后但在更改检测之前执行。
有关更改检测读取的更多信息
您需要了解的有关Angular中的更改检测的所有信息 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.