dimanche 20 octobre 2019

Angular 8: le timing des décorateurs @ViewChild @ViewChildren


 Angular 8, il est obligatoire de renseigner une propriété static sur le ViewChild et ContentChlid

https://stackoverflow.com/questions/56359504/how-should-i-use-the-new-static-option-for-viewchild-in-angular-8

Queries timing


The ViewChild and ContentChild decorators now must have a new option called static. Let me explain why with a very simple example using a ViewChild:
*ngIf="true">
#dynamicDiv>dynamic
Let’s get that element in our component and log it in the lifecycle hooks ngOnInit and ngAfterViewInit:
@ViewChild('dynamicDiv') dynamicDiv: ElementRef<HTMLDivElement>;

ngOnInit() {
  console.log('init dynamic', this.dynamicDiv); // undefined
}

ngAfterViewInit() {
  console.log('after view init dynamic', this.dynamicDiv); // div
}
Makes sense as AfterViewInit is called when the template initialization is done.
But in fact, if the queried element is static (not wrapped in an ngIf or an ngFor), then it is available in ngOnInit also:

#staticDiv>static

gives:
@ViewChild('staticDiv') staticDiv: ElementRef<HTMLDivElement>;

ngOnInit() {
  console.log('init static', this.staticDiv); // div
}

ngAfterViewInit() {
  console.log('after view init static', this.staticDiv); // div
}
This was not documented, or recommended, but that’s how it currently works.
With Ivy though, the behavior changes to be more consistent:
ngOnInit() {
  console.log('init static', this.staticDiv); // undefined (changed)
}

ngAfterViewInit() {
  console.log('after view init static', this.staticDiv); // div
}
A new static flag has been introduced to not break existing applications, so if you want to keep the old behavior even when you’ll switch to Ivy, you can write:
@ViewChild('static', { static: true }) static: ElementRef<HTMLDivElement>;
and the behavior will be the same as the current one (the element is also accessible in ngOnInit).
Note that if you add static: true on a dynamic element (wrapped in a condition or a loop), then it will not be accessible in ngOnInit nor in ngAfterViewInit!
static: false will be how Ivy behaves by default.
To not break existing applications and to ease the migration, the Angular team wrote a schematic that automatically analyzes your application, and adds the static flag. It even offers two strategies:
  • one based on your templates, which will make sure that your application works (so it tends to mark queries as static even when they aren’t). You are sure it works, but it exposes you to problems if you wrap your static element in a condition or a loop later.
  • one based on your usage of the query, which is more error-prone (as it is harder for the schematic to figure it out), but will not mark the queries as static if they don’t need to be. So most queries will have static: false, which will be the default in Ivy.
The first strategy is used by default when you run ng update because it is the safest, but you can try the usage strategy by using NG_STATIC_QUERY_USAGE_STRATEGY=true ng update.
You can check out the official guide for more information.
This is what the migration looks like (with a failure in one component):
------ Static Query Migration ------
With Angular version 8, developers need to
explicitly specify the timing of ViewChild and
ContentChild queries. Read more about this here:
https://v8.angular.io/guide/static-query-migration

Some queries could not be migrated automatically. Please go
those manually and apply the appropriate timing.
For more info on how to choose a flag, please see:
https://v8.angular.io/guide/static-query-migration
   home/home.component.ts@43:3: undefined
Note that this only concerns ViewChild and ContentChild, not ViewChildren and ContentChildren (which will work the same way in Ivy and View Engine).

Aucun commentaire:

Enregistrer un commentaire

to criticize, to improve