为什么即使*ngIf设置为true,@ViewChild仍然未定义



我遇到了以下问题,该问题由@ViewChild中的{static: false}属性修复。这个stackoverflow问答帮助了我如何在Angular 8中使用@ViewChild的新静态选项?。

我想更好地了解这个场景,static如何改变结果,以及变化检测如何影响这个场景。我读了一些关于角度文档中的变化检测的文章,发现这一点非常缺乏。

我想出了一个stackblitz来说明一些我不理解的东西Stacklitz角度示例

当点击toggle按钮两次时,我在命令行上得到以下内容:

> undefined undefined
> undefined undefined
> undefined ElementRef {nativeElement: div}
> undefined ElementRef {nativeElement: div}

然而我期待:

> undefined undefined
> undefined ElementRef {nativeElement: div}
> ElementRef {nativeElement: div} ElementRef {nativeElement: div}
> ElementRef {nativeElement: div} ElementRef {nativeElement: div}

以下是代码的逻辑——(请参阅stackblitz中的完整代码(

@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
@ViewChild("contentPlaceholder", { static: true })
trueViewChild: ElementRef;
@ViewChild("contentPlaceholder", { static: false })
falseViewChild: ElementRef;
display = false;
constructor() {}
show() {
console.log(this.trueViewChild, this.falseViewChild);
this.display = true;
console.log(this.trueViewChild, this.falseViewChild);
} 
}

我的问题是:

  1. 为什么this.falseViewChild的第二行值显示为未定义。更改检测不应该在设置this.display = false之后运行,因此不应该未定义吗
  2. 为什么this.trueViewChild未定义。我希望它在*ngIf变为真之后找到元素

角度变化检测在zone.js库的帮助下工作更新ViewChild/Content查询发生在更改检测周期内

zone.js库修补异步API(addEventListener、setTimeout((、Promises…(并且确切地知道哪个任务被执行以及何时完成。

例如,它可以监听点击事件,并在此任务完成时发出通知(没有挂起的任务,这意味着区域变得稳定(。

Angular订阅这些通知,以便从根组件开始对所有组件执行更改检测

// your code 
(click)="someHandler()" 
someHandler() {              
....
}
// angular core
checkStable() {
if (there is no any task being executed and there is no any async pending request) {
PERFORM CHANGE DETECTION
} 
}

关于的代码中的顺序如下:

click
||
/
someHandler()
||
/
checkStable()
||
/
PERFORM CHANGE DETECTION

那么,让我们来回答您的问题:

  1. 为什么this.falseViewChild的第二行值显示为未定义。设置this.display=false后不应该运行更改检测,因此不应该未定义它吗

更改display属性时没有反应性

show() {
console.log(this.trueViewChild, this.falseViewChild);
this.display = true;  <--- Angular doesn't do here anything, it only listens to zone state changes
console.log(this.trueViewChild, this.falseViewChild); // nothing should be updated here 
// because there wasn't any cd cycle yet
} 

这就是为什么你第一次点击就会得到以下输出:

> undefined undefined
> undefined undefined   <---- nothing has updated
......
update happens here

它稍后会更新,但除非您再次单击,否则您不会看到此信息,因为您稍后不会记录这些值。

  1. Why does this.trueViewChild stay undefined. I would expect it to find the element after the *ngIf becomes true?

因为Angular文档中有这样的规则:

使用静态查询(static:true(,一旦视图已创建,但在运行更改检测之前。结果,但是,永远不会更新以反映对视图的更改,例如更改ngIf和ngFor块。

这意味着,如果它最初是false(例如,它在*ngIf或ng-template内部(,那么它将始终是false

最新更新