为什么在组件内部调用 detectChanges() 不会更新值,但在 setTimeout() 中包装代码会更新值?

Why calling detectChanges() inside component doesn't update values, but wrapping code in setTimeout() does it?

我正在尝试自动 select <mat-autocomplete ...>

中选项集中的第一个值
export class ExampleComponent implements OnInit, AfterViewInit {

@ViewChildren('auto') matAutocomplete: QueryList<any>;

constructor(private cdr: ChangeDetectorRef) { }

ngAfterViewInit() {
    this.foundItemsList.changes.subscribe(options => {
        // ---> This simply works!
        setTimeout(() => this.matAutocomplete.first._keyManager.setFirstItemActive(), 0);

        // ---> This doesn't works?! No error shown, it just seems that the above function isn't called at all. 
        this.matAutocomplete.first._keyManager.setFirstItemActive()
        this.cdr.detectChanges();
    });
}

https://github.com/angular/material2/blob/master/src/lib/autocomplete/autocomplete.ts

AFAIK,detectChanges 所做的是检查当前组件及其所有子组件的变化检测器,对吗?但是上面的场景好像不行。

this.cdr.detectChanges() 仅 运行 对当前组件(和后代)进行更改检测。如果 setFirstItemActive() 导致其他地方发生变化,则不包括在内。 setTimeout()zone.run(...)ApplicationRef.tick() 导致整个应用程序的更改检测为 运行,因此每个绑定都被覆盖,而不仅仅是当前组件。

请注意您使用的是内容投影 (ng-content) 还是@HostBindings。

当您 运行 更改托管内容的组件的检测或设置主机绑定时,它实际上可能不会生效,因为它是父组件(甚至可能位于不同的模块中)'owns'那些属性。

但是,与 markForCheck() 相关的行为已于 2017 年 5 月更改为标记以检查父组件中投影的 ng-contenthttps://github.com/juleskremer/angular/commit/f894dbdd78cf463ed53b6c50d883326ff7fbff87

因此,detectChanges() 似乎不足以包含内容,您应该使用 markForCheck 来代替,这将触发对包含内容的检查。