繁体   English   中英

Angular4如何知道ViewChild何时被重置

[英]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后,我的模板尚未刷新。 但是,如果我使用setTimeoutmyCustomComp会更新,我的问题就会消失。 这是中等的hacky,我想知道我正在尝试做什么的正确方法。

这就是为什么在调用displayAndUseMyCustomComp后它未定义的原因

Angular将ViewChild查询列表更新为更改检测的一部分。 当Angular运行初始更改检测时, isMyCustomCompDisplayedfalse ,因此隐藏了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的下一个更改检测周期中更新视图子查询列表后执行的所有生命周期钩子可用。 目前这些是ngAfterViewInitngAfterViewChecked 由于前者只被调用一次,我们需要使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM