web-dev-qa-db-ja.com

コンポーネント内でdetectChanges()を呼び出しても値が更新されないのに、setTimeout()でコードをラップすると更新されるのはなぜですか?

<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は、現在のコンポーネントとそのすべての子コンポーネントの変更検出器をチェックしますか?しかし、上記のシナリオでは機能していないようです。

6
kav

this.cdr.detectChanges()は、現在のコンポーネント(および子孫)の変更検出のみを実行します。 setFirstItemActive()が他の場所で変更を引き起こす場合、これはカバーされません。 setTimeout()またはzone.run(...)またはApplicationRef.tick()により、アプリケーション全体に対して変更検出が実行されるため、現在のコンポーネントだけでなく、すべてのバインディングがカバーされます。

6

コンテンツプロジェクション(_ng-content_)または@HostBindingsを使用しているかどうかに注意してください。

コンテンツをホストしているコンポーネントに対して変更検出を実行する場合、またはホストバインディングを設定する場合、それらの属性を「所有」するのは親コンポーネント(別のモジュールにある場合もあります)であるため、実際には有効にならない場合があります。

ただし、markForCheck()に関連する動作は、2017年5月に変更され、親コンポーネントで投影された_ng-content_をチェックするようにマークされました。 https://github.com/juleskremer/angular/commit/f894dbdd78cf463ed53b6c50d883326ff7fbff87

したがって、detectChanges()はインクルードされたコンテンツには不十分であるように思われ、代わりにmarkForCheckを使用する必要があります。これにより、インクルードされたコンテンツがチェックされます。

2
Simon_Weaver