Angular 8の@ViewChildに新しい静的オプションをどのように使用すればよいですか?


204

新しいAngular 8ビューの子をどのように構成すればよいですか?

@ViewChild('searchText', {read: ElementRef, static: false})
public searchTextInput: ElementRef;

@ViewChild('searchText', {read: ElementRef, static: true})
public searchTextInput: ElementRef;

どちらが良いですか?static:truevsはいつ使用すべきstatic:falseですか?

回答:


237

ほとんどの場合、使用する必要があります{static: false}。このように設定すると、バインディングの解決に依存するクエリ構造(構造ディレクティブなど*ngIf, etc...)が確実に検出されます。

いつ使用するかの例static: false

@Component({
  template: `
    <div *ngIf="showMe" #viewMe>Am I here?</div>
    <button (click)="showMe = !showMe"></button>
  ` 
})
export class ExampleComponent {
  @ViewChild('viewMe', { static: false })
  viewMe?: ElementRef<HTMLElement>; 

  showMe = false;
}

これstatic: falseは、Angular 9のデフォルトのフォールバック動作になります。詳しくは、こちらこちらをご覧ください。

{ static: true }オプションは、その場で埋め込みビューの作成をサポートするために導入されました。ビューを動的に作成していて、にアクセスしたいTemplateRef場合はngAfterViewInitExpressionHasChangedAfterCheckedエラーが発生するため、アクセスできません。staticフラグをtrueに設定すると、ngOnInitにビューが作成されます。

それにもかかわらず:

他のほとんどの場合、ベストプラクティスはを使用すること{static: false}です。

ただし、この{ static: false }オプションはAngular 9ではデフォルトになることに注意してください。つまり、オプションを使用したくない場合を除き、静的フラグを設定する必要はありませんstatic: true

angular cli ng updateコマンドを使用して、現在のコードベースを自動的にアップグレードできます。

移行ガイドとこれに関するさらに詳しい情報については、ここここで確認できます

静的クエリと動的クエリの違いは何ですか?

@ViewChild()および@ContentChild()クエリの静的オプションは、クエリ結果がいつ利用可能になるかを決定します。

静的クエリ(静的:true)では、ビューが作成された後、変更検出が実行される前にクエリが解決されます。ただし、結果は、ngIfブロックやngForブロックの変更など、ビューの変更を反映するように更新されることはありません。

動的クエリ(静的:false)の場合、クエリは、@ ViewChild()および@ContentChild()のngAfterViewInit()またはngAfterContentInit()の後にそれぞれ解決します。結果は、ngIfブロックやngForブロックの変更など、ビューの変更に対して更新されます。


角度のドキュメントのリンクを更新してください(リリース後に変更されました)angular.io/api/core/ViewChild#description
Sachin Gupta

2
childViewのインスタンスにアクセスできません。それはいつも未定義と言っています。
Nesan Mano

Angular 9で静的オプションを削除することに関する情報へのリンクを提供していただけますか?
Alex Marinov

@AlexMarinov私は自分の回答を更新して、angular 9で何が起こるかをより明確にしました。これに関するリンクは、移行ガイド
Poul Kruijt

1
@MinhNghĩaコンポーネントのテンプレートの外側にコンポーネント全体をネストする場合はを使用できますが{ static: true }、内部ngOnInitでViewChildにアクセスする必要がない場合は、を使用するだけ{ static: false }です。
Poul Kruijt

88

経験則として、次のことを行うことができます。

  • { static: true }あなたがアクセスしたいときのニーズが設定されるViewChild中をngOnInit

  • { static: false }でのみアクセスできますngAfterViewInit。これは*ngIf、テンプレートの要素に構造ディレクティブ(つまり)がある場合にも適用したいものです。


2
注:Angular 9では、静的フラグはデフォルトでfalseに設定されているため、「すべての{static:false}フラグを安全に削除できます」。ドキュメント:angular.io/guide/static-query-migration
Stevethemacguy

17

角度のドキュメントから

static-変更検出の実行前にクエリ結果を解決するかどうか(つまり、静的な結果のみを返す)。このオプションが指定されていない場合、コンパイラーはデフォルトの動作にフォールバックします。これは、クエリ結果を使用してクエリ解決のタイミングを決定することです。クエリ結果がネストされたビュー(* ngIfなど)内にある場合、クエリは変更検出の実行後に解決されます。それ以外の場合は、変更検出が実行される前に解決されます。

static:true子供が条件に依存しない場合は、使用することをお勧めします。要素の可視性が変化すると、static:falseより良い結果が得られる可能性があります。

PS:その新機能なので、パフォーマンスのためにベンチマークを実行する必要があるかもしれません。

編集する

@Massimiliano Sartorettoが述べたように、github commitはより多くの洞察を与えるかもしれません。


3
この機能の背後に公式の動機を追加しますgithub.com/angular/angular/pull/28810
Massimiliano

2

Angular 8にアップグレードした後、ngOnInitでViewChildがnullになったため、ここに来ました。

静的クエリはngOnInitの前に入力され、動的クエリ(静的:false)はその後に入力されます。言い換えると、static:falseを設定した後にngOnInitでviewchildがnullになった場合、static:trueに変更するか、コードをngAfterViewInitに移動することを検討する必要があります。

https://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L332-L336を参照してください

他の答えは正解であり、これが当てはまる理由を説明しています。ngIf内のViewChild参照などの構造ディレクティブに依存するクエリは、このディレクティブの条件が解決された後、つまり変更が検出された後に実行する必要があります。ただし、static:trueを安全に使用できるため、ネストされていない参照のngOnInitの前にクエリを解決できます。この特定のケースがnull例外であることを指摘した場合、私にとっては、この特殊性に遭遇する最初の方法である可能性があります。


1

子@angular 5+トークンの2つの引数を表示( 'ローカル参照名'、static:false | true)

@ViewChild('nameInput', { static: false }) nameInputRef: ElementRef;

真と偽の違いを知るには、これをチェックしてください

static-変更検出の実行前にクエリ結果を解決するかどうか(つまり、静的な結果のみを返す)。このオプションが指定されていない場合、コンパイラーはデフォルトの動作にフォールバックします。これは、クエリ結果を使用してクエリ解決のタイミングを決定することです。クエリ結果がネストされたビュー(* ngIfなど)内にある場合、クエリは変更検出の実行後に解決されます。それ以外の場合は、変更検出が実行される前に解決されます。


0

ng8では、親コンポーネントの子コンポーネントにアクセスするタイミングを手動で設定できます。staticをtrueに設定すると、親コンポーネントはコンポーネントの定義のみをonInitフックで取得します。例:

 // You got a childComponent which has a ngIf/for tag
ngOnInit(){
  console.log(this.childComponent);
}

ngAfterViewInit(){
  console.log(this.childComponent);
}

staticがfalseの場合、ngAfterViewInit()でのみ定義を取得し、ngOnInit()では未定義になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.