ChatGPT解决这个技术问题 Extra ChatGPT

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

How should I configure the new Angular 8 view child?

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

vs

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

Which is better? When should I use static:true vs static:false?


P
Poul Kruijt

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 and here

#What is the difference between static and dynamic queries? The static option for @ViewChild() and @ContentChild() queries determines when the query results become available.

With static queries (static: true), the query resolves once the view has been created, but before change detection runs. The result, though, will never be updated to reflect changes to your view, such as changes to ngIf and ngFor blocks.

With dynamic queries (static: false), the query resolves after either ngAfterViewInit() or ngAfterContentInit() for @ViewChild() and @ContentChild() respectively. The result will be updated for changes to your view, such as changes to ngIf and ngFor blocks.

A nice use-case for using static: true, is if you are using fromEvent to bind to an element defined in the template. Consider the following template:

<div [ngStyle]="thumbStyle$ | async" #thumb></div>

You can then handle events on this element without the need of using subscriptions or init hooks (if you don't want to or cannot use angular event binding):

@Component({})
export class ThumbComponent {
  @ViewChild('thumb', { static: true })
  thumb?: ElementRef<HTMLElement>;

  readonly thumbStyle$ = defer(() => fromEvent(this.thumb, 'pointerdown').pipe(
    switchMap((startEvent) => fromEvent(document, 'pointermove', { passive: true })
    // transform to proper positioning
  ));
}

It is important to use defer. This will make sure the observable is only resolved when it's subscribed to. This will happen before the ngAfterViewInit gets triggered, when the async pipe subscribes to it. Because we are using static: true, the this.thumb is already populated.


Please update the link for angular docs (changed after release) angular.io/api/core/ViewChild#description
I am not able to access the instance of childView. It says undefined all the time.
Can you please provide a link about that information of removing the static option in Angular 9?
@AlexMarinov I've updated my answer to make it more clear what's going to happen in angular 9. The link about this is in the migration guide
@MinhNghĩa if you nest the entire component outside of the component's template, you can use { static: true }, but if there is no direct need for having access to the ViewChild inside ngOnInit, you should just use the { static: false }.
d
dave0688

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.


Note: In Angular 9, the static flag defaults to false, so "any {static: false} flags can be safely removed". Documentation: angular.io/guide/static-query-migration
S
Sachin Gupta

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.


I would add the official motivations behind this feature github.com/angular/angular/pull/28810
c
corolla

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.


S
Samar Abdallah

view child @angular 5+ token two arguments ('local reference name',static: false|true)

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

to know the difference between true and false check this

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.


T
Tethys Zhang

In ng8 , you can manually set when to access the child component in the parent component. When you set static to true, it means the parent component only get the definition of the component in the onInit hook: Eg:

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

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

If static is false , then you only get the defination in the ngAfterViewInit(), in ngOnInit(), you'll get undefined.


J
JMP

View child

... Can use it for template element reference.

...for outside of particular component reference.

With decorator style syntax.. @ViewChild( selector) reference : ElementRef || QueryList.

Of specific component or element reference.

Use it in AfterViewInIt().

We could use it in Oninit().

But this for specific to use ngAfterViewInit().

Lastly {static : false} should be placed in @ViewChild( Useme , { static : false})... for template variable reference.

The variable in template file looks like. #Useme.


P
Pavan

static property informs angular about the availability of our child

For example: if static is set to true, we are informing angular our child is available on the page from the beginning ( meaning it is not dependent of *ngIf,page bindings,API calls etc) so angular looks for it at the earliest lifecycle hook ( ngOnInit) and never looks for it again

In case we set static to false we are informing angular that our child is dependent on some conditional directives, so angular tries to look for our child after every change detection cycle and if it is available we can access it in ngAfterViewInit() life cycle hook


is just the opposite manner: {static: true} Angular only check one time (At very early stage of the component -this is the reason you can get it in ngOnInit-) and the element can not be under a *ngIf, etc.