How should I use the new static option for @ViewChild in Angular 8?

给你一囗甜甜゛ 提交于 2019-11-28 04:27:13

In most cases you will want to use {static: false}. Setting it like this will ensure query matches that are dependent on binding resolution (like structural directives *ngIf, etc...) will be found.

Example of when to use 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;
}

The static: false is going to be the default fallback behaviour in Angular 9. Read more here and here

The { static: true } option was introduced to support creating embedded views on the fly. When you are creating a view dynamically and want to acces the TemplateRef, you won't be able to do so in ngAfterViewInit as it will cause a ExpressionHasChangedAfterChecked error. Setting the static flag to true will create your view in ngOnInit.

Nevertheless:

In most other cases, the best practice is to use {static: false}.

Be aware though that the { static: false } option will be made default in Angular 9. Which means that setting the static flag is no longer necessary, unless you want to use the static: true option.

You can use the angular cli ng update command to automatically upgrade your current code base.

For a migration guide and even more information about this, you can check here

From the angular docs

static - whether or not to resolve query results before change detection runs (i.e. return static results only). If this option is not provided, the compiler will fall back to its default behavior, which is to use query results to determine the timing of query resolution. If any query results are inside a nested view (e.g. *ngIf), the query will be resolved after change detection runs. Otherwise, it will be resolved before change detection runs.

It may be a better idea to use static:true if the child does not depend on any conditions. If the visibility of element changes, then static:false may give better results.

PS: Since its a new feature, we may need to run benchmarks for performance.

Edit

As mentioned by @Massimiliano Sartoretto , github commit may give you more insights.

So as a rule of thumb you can go for the following:

  • { static: true } needs to be set when you want to access the ViewChild in ngOnInit.

  • { static: false } can only be accessed in ngAfterViewInit. This is also what you want to go for when you have a structural directive (i.e. *ngIf) on your element in your template.

Came here because a ViewChild was null in ngOnInit after upgrading to Angular 8.

Static queries are filled before ngOnInit, while dynamic queries (static: false) are filled after. In other words, if a viewchild is now null in ngOnInit after you set static: false, you should consider changing to static: true or move code to ngAfterViewInit.

See https://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L332-L336

The other answers are correct and explain why this is the case: Queries dependant on structural directives, e.g. a ViewChild reference inside an ngIf, should run after the conditional of this directive has been resolved, ie after change detection. However, one may safely use static: true and thus resolve the queries before ngOnInit for unnested references. Imho this particular case bears mentioning as a null exception could likely be the first way you'll encounter this particularity, as it was for me.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!