238
votes

Comment utiliser la nouvelle option statique pour @ViewChild dans Angular 8?

Comment dois-je configurer le nouvel enfant de la vue Angular 8?

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

contre

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

Ce qui est mieux? Quand dois-je utiliser static:true vs static:false ?


0 commentaires

7 Réponses :


276
votes

Dans la plupart des cas, vous souhaiterez utiliser {static: false} . Le paramétrer ainsi garantira que les correspondances de requêtes qui dépendent de la résolution de la liaison (comme les directives structurelles *ngIf, etc... ) seront trouvées.

Exemple d'utilisation de 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;
}

Le static: false sera le comportement de secours par défaut dans Angular 9. En savoir plus ici et ici

L'option { static: true } été introduite pour prendre en charge la création de vues intégrées à la volée. Lorsque vous créez une vue dynamiquement et que vous souhaitez accéder au TemplateRef , vous ne pourrez pas le faire dans ngAfterViewInit car cela provoquera une erreur ExpressionHasChangedAfterChecked . La définition de l'indicateur statique sur true créera votre vue dans ngOnInit.

Cependant:

Dans la plupart des autres cas, la meilleure pratique consiste à utiliser {static: false} .

Sachez cependant que l'option { static: false } sera définie par défaut dans Angular 9. Ce qui signifie que la définition de l'indicateur static n'est plus nécessaire, à moins que vous ne souhaitiez utiliser l'option static: true .

Vous pouvez utiliser la commande angular cli ng update pour mettre à jour automatiquement votre base de code actuelle.

Pour un guide de migration et encore plus d'informations à ce sujet, vous pouvez vérifier ici et ici

Quelle est la différence entre les requêtes statiques et dynamiques?

L'option statique pour les requêtes @ViewChild () et @ContentChild () détermine quand les résultats de la requête deviennent disponibles.

Avec les requêtes statiques (static: true), la requête est résolue une fois la vue créée, mais avant l'exécution de la détection des modifications. Le résultat, cependant, ne sera jamais mis à jour pour refléter les modifications apportées à votre vue, telles que les modifications apportées aux blocs ngIf et ngFor.

Avec les requêtes dynamiques (statique: false), la requête est résolue après ngAfterViewInit () ou ngAfterContentInit () pour @ViewChild () et @ContentChild () respectivement. Le résultat sera mis à jour pour les modifications apportées à votre vue, telles que les modifications apportées aux blocs ngIf et ngFor.


8 commentaires

Veuillez mettre à jour le lien pour les documents angulaires (modifiés après la publication) angular.io/api/core/ViewChild#description


Je ne parviens pas à accéder à l'instance de childView. Il dit indéfini tout le temps.


Pouvez-vous s'il vous plaît fournir un lien sur ces informations sur la suppression de l'option statique dans Angular 9?


@AlexMarinov J'ai mis à jour ma réponse pour clarifier ce qui va se passer dans angular 9. Le lien à ce sujet se trouve dans le guide de migration


@NesanMano Je rencontre le même problème aujourd'hui, la façon dont j'ai résolu était de définir { static: true } . J'espère que cela t'aides


Si *ngIf le composant dans un *ngIf , et que ce bloc n'est défini sur true que plus tard, comment puis-je prendre le ViewChild ?


@ MinhNghĩa si vous imbriquez le composant entier en dehors du modèle du composant, vous pouvez utiliser { static: true } , mais s'il n'est pas nécessaire d'avoir directement accès au ViewChild dans ngOnInit , vous devez simplement utiliser { static: false } .


Documentation officielle Angular 9: angular.io/guide/static-query-migration



18
votes

À partir des documents angulaires

statique - s'il faut ou non résoudre les résultats de la requête avant l'exécution de la détection des modifications (c'est-à-dire renvoyer uniquement les résultats statiques). Si cette option n'est pas fournie, le compilateur reviendra à son comportement par défaut, qui consiste à utiliser les résultats de la requête pour déterminer le moment de la résolution de la requête. Si des résultats de requête se trouvent dans une vue imbriquée (par exemple * ngIf), la requête sera résolue après l'exécution de la détection des modifications. Sinon, il sera résolu avant l'exécution de la détection des modifications.

Il peut être préférable d'utiliser static:true si l'enfant ne dépend d'aucune condition. Si la visibilité de l'élément change, alors static:false peut donner de meilleurs résultats.

PS: Puisqu'il s'agit d'une nouvelle fonctionnalité, nous devrons peut-être exécuter des tests de performances.

Éditer

Comme mentionné par @Massimiliano Sartoretto, github commit peut vous donner plus d'informations.


1 commentaires

J'ajouterais les motivations officielles derrière cette fonctionnalité github.com/angular/angular/pull/28810



2
votes

Je suis venu ici car un ViewChild était nul dans ngOnInit après la mise à niveau vers Angular 8.

Les requêtes statiques sont remplies avant ngOnInit, tandis que les requêtes dynamiques (static: false) sont remplies après. En d'autres termes, si un viewchild est maintenant nul dans ngOnInit après avoir défini static: false, vous devez envisager de passer à static: true ou de déplacer le code vers ngAfterViewInit.

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

Les autres réponses sont correctes et expliquent pourquoi c'est le cas: Les requêtes dépendant de directives structurelles, par exemple une référence ViewChild à l'intérieur d'un ngIf, devraient s'exécuter après la résolution du conditionnel de cette directive, c'est-à-dire après la détection de changement. Cependant, on peut en toute sécurité utiliser static: true et résoudre ainsi les requêtes avant ngOnInit pour les références non imbriquées. À mon avis, ce cas particulier mérite d'être mentionné comme une exception nulle pourrait probablement être la première façon dont vous rencontrerez cette particularité, comme c'était le cas pour moi.


0 commentaires

98
votes

Donc, en règle générale, vous pouvez opter pour ce qui suit:

  • { static: true } doit être défini lorsque vous souhaitez accéder à ViewChild dans ngOnInit .

  • { static: false } n'est accessible que dans ngAfterViewInit . C'est aussi ce que vous voulez faire lorsque vous avez une directive structurelle (ie *ngIf ) sur votre élément dans votre modèle.


1 commentaires

Remarque: Dans Angular 9, l'indicateur statique est défini par défaut sur false, de sorte que "tous les indicateurs {static: false} peuvent être supprimés en toute sécurité". Documentation: angular.io/guide/static-query-migration



1
votes

voir l'enfant @angular 5+ jeton deux arguments ('nom de référence locale', statique: faux | vrai)

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

pour connaître la différence entre vrai et faux cochez ceci

statique - s'il faut ou non résoudre les résultats de la requête avant l'exécution de la détection des modifications (c'est-à-dire renvoyer uniquement les résultats statiques). Si cette option n'est pas fournie, le compilateur reviendra à son comportement par défaut, qui consiste à utiliser les résultats de la requête pour déterminer le moment de la résolution de la requête. Si des résultats de requête se trouvent dans une vue imbriquée (par exemple * ngIf), la requête sera résolue après l'exécution de la détection des modifications. Sinon, il sera résolu avant l'exécution de la détection des modifications.


0 commentaires

0
votes

Dans ng8, vous pouvez définir manuellement quand accéder au composant enfant dans le composant parent. Lorsque vous définissez static sur true, cela signifie que le composant parent obtient uniquement la définition du composant dans le hook onInit : Par exemple:

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

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

Si static est faux, alors vous n'obtiendrez la définition que dans ngAfterViewInit (), dans ngOnInit (), vous obtiendrez undefined.


0 commentaires

0
votes

Voir l'enfant

... Peut l'utiliser pour la référence d'élément de modèle.

... pour l'extérieur d'une référence de composant particulière.

Avec la syntaxe de style décorateur .. @ViewChild( selector) reference : ElementRef || QueryList.

De référence de composant ou d'élément spécifique.

Utilisez-le dans AfterViewInIt() .

Nous pourrions l'utiliser dans Oninit() .

Mais ceci pour l'utilisation spécifique de ngAfterViewInit() .

Enfin {static : false} doit être placé dans @ViewChild( Useme , { static : false}) ... pour référence de variable de modèle.

La variable dans le fichier modèle ressemble à. #Useme .


0 commentaires