[英]Angular4 How to know when a ViewChild has been reset
Here is the template of main.html
: 这是main.html
的模板:
<button (click)="displayAndUseMyCustomComp()"></button>
<my-custom-comp *ngIf="isMyCustomCompDisplayed" #myCustomComp="myCustomComp"></my-custom-comp>
and main.component.ts
: 和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}
})
}
}
What's happening is that my template isn't yet refreshed after I set isMyCustomCompDisplayed
to true
. 发生了什么事情,我将isMyCustomCompDisplayed
设置为true
后,我的模板尚未刷新。 However, if I use a setTimeout
, myCustomComp
gets updated and my issue goes away. 但是,如果我使用setTimeout
, myCustomComp
会更新,我的问题就会消失。 It is midly hacky, and I was wondering what was the correct way of doing what I am trying to. 这是中等的hacky,我想知道我正在尝试做什么的正确方法。
displayAndUseMyCustomComp
这就是为什么在调用displayAndUseMyCustomComp
后它未定义的原因 Angular updates ViewChild
query list as part of change detection. Angular将ViewChild
查询列表更新为更改检测的一部分。 When Angular was running initial change detection the isMyCustomCompDisplayed
was false
and so myCustomComp
was hidden. 当Angular运行初始更改检测时, isMyCustomCompDisplayed
为false
,因此隐藏了myCustomComp
。 The myCustomComp
was set to undefined
. myCustomComp
设置为undefined
。
After you make a click the function displayAndUseMyCustomComp
is executed and isMyCustomCompDisplayed
is set to true
. 单击后,执行displayAndUseMyCustomComp
函数,并将isMyCustomCompDisplayed
设置为true
。 Angular requires a change detection cycle to update the myCustomComp
query list. Angular需要更改检测周期来更新myCustomComp
查询列表。 However, you try to read the value immediately and so it's still undefined
. 但是,您尝试立即读取该值,因此仍未undefined
。 You need to wait for another change detection cycle for Angular to update the query list. 您需要等待Angular的另一个更改检测周期来更新查询列表。
setTimeout
如果将调用包装到setTimeout
这就是它的工作setTimeout
If you try to read the myCustomComp
inside the timeout, Angular has a chance to run change detection between the update to isMyCustomCompDisplayed
and the time you read myCustomComp
. 如果您尝试在超时内读取myCustomComp
,Angular有机会在更新isMyCustomCompDisplayed
和读取myCustomComp
之间运行更改检测。
When Angular runs change detection for the MainComponent
it detects that isMyCustomCompDisplayed
is updated. 当Angular运行MainComponent
更改检测时,它会检测到isMyCustomCompDisplayed
已更新。 So it goes and updates bindings for ngIf
. 所以它会更新ngIf
绑定。 It in turn reacts to this change and creates and embedded view with the myCustomComp
and attaches it to the MainComponent
component: 它反过来对此更改做出反应,并使用myCustomComp
创建和嵌入视图,并将其附加到MainComponent
组件:
@Input()
set ngIf(condition: any) {
if (condidition) {
this._viewContainer.createEmbeddedView(this._thenTemplateRef, this._context);
If you're looking for synchronous solution, it will be available inside all lifecycle hooks that are executed after the view children query list is updated during the next change detection cycle that follows execution of displayAndUseMyCustomComp
. 如果您正在寻找同步解决方案,它将在执行displayAndUseMyCustomComp
的下一个更改检测周期中更新视图子查询列表后执行的所有生命周期钩子中可用。 At the moment these are ngAfterViewInit
and ngAfterViewChecked
. 目前这些是ngAfterViewInit
和ngAfterViewChecked
。 Since the former is called only once, we need to use ngAfterViewChecked
: 由于前者只被调用一次,我们需要使用ngAfterViewChecked
:
ngAfterViewChecked() {
if(this.isMyCustomCompDisplayed) {
console.log(this.myCustomComp) // prints {object}
}
}
displayAndUseMyCustomComp() {
this.isMyCustomCompDisplayed = true
}
Another synchronous solution suggested by @ThinkingMedia
is also good. @ThinkingMedia
建议的另一个同步解决方案也很好。 You can use ViewChildren
instead of ViewChild
and subscribe to changes
(btw you don't template reference): 您可以使用ViewChildren
而不是ViewChild
并订阅changes
(顺便ViewChild
您没有模板引用):
@ViewChildren(myCustomComp) as: QueryList<myCustomComp>;
ngAfterViewInit() {
this.myCustomComp.changes.subscribe(() => {
console.log(this.myCustomComp.first); // prints {object}
});
}
The callback will be triggered during next digest when Angular will be updating query list (slightly earlier than ngAfterViewChecked
). 当Angular将更新查询列表(稍早于ngAfterViewChecked
)时,将在下一个摘要期间触发回调。
If you're looking for asynchronous solution, use setTimeout
as you do it. 如果您正在寻找异步解决方案,请在执行此操作时使用setTimeout
。 The Promise.resolve(null).then(()=>{ console.log(this.myCustomComp) })
(microtask) solution won't work because it will be executed after the current stack but before the change detection. Promise.resolve(null).then(()=>{ console.log(this.myCustomComp) })
(microtask)解决方案将无法工作,因为它将在当前堆栈之后但在更改检测之前执行。
For more information on change detection read 有关更改检测读取的更多信息
Everything you need to know about change detection in Angular . 您需要了解的有关Angular中的更改检测的所有信息 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.