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

204

Comment dois-je configurer le nouvel enfant Angular 8 view?

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

contre

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

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

Patrik Laszlo
la source

Réponses:

237

Dans la plupart des cas, vous voudrez utiliser {static: false}. Si vous le définissez comme ceci, les correspondances de requête qui dépendent de la résolution de liaison (comme les directives structurelles *ngIf, etc...) seront trouvées.

Exemple d'utilisation 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: falseva être le comportement de secours par défaut dans Angular 9. En savoir plus ici et ici

L' { static: true }option a été introduite pour prendre en charge la création de vues intégrées à la volée. Lorsque vous créez une vue de manière dynamique et souhaitez accéder à TemplateRef, vous ne pourrez pas le faire ngAfterViewInitcar cela entraînera une ExpressionHasChangedAfterCheckederreur. La définition de l'indicateur statique sur true créera votre vue dans ngOnInit.

Néanmoins:

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

Sachez cependant que l' { static: false }option sera définie par défaut dans Angular 9. Ce qui signifie que la définition de l'indicateur statique n'est plus nécessaire, sauf si vous souhaitez utiliser l' static: trueoption.

Vous pouvez utiliser la ng updatecommande angular cli pour mettre à niveau automatiquement votre base de code actuelle.

Pour un guide de migration et encore plus d'informations à ce sujet, vous pouvez consulter 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 se résout 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 (statiques: 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.

Poul Kruijt
la source
Veuillez mettre à jour le lien pour les documents angulaires (modifiés après la publication) angular.io/api/core/ViewChild#description
Sachin Gupta
2
Je ne parviens pas à accéder à l'instance de childView. Il dit indéfiniment tout le temps.
Nesan Mano
Pouvez-vous s'il vous plaît fournir un lien sur ces informations de suppression de l'option statique dans Angular 9?
Alex Marinov
@AlexMarinov J'ai mis à jour ma réponse pour clarifier ce qui va se passer en angulaire 9. Le lien à ce sujet est dans le guide de migration
Poul Kruijt
1
@ MinhNghĩa si vous imbriquez le composant entier en dehors du modèle du composant, vous pouvez l'utiliser { static: true }, mais s'il n'y a pas de besoin direct d'avoir accès au ViewChild à l'intérieur ngOnInit, vous devez simplement utiliser le { static: false }.
Poul Kruijt
88

Donc, en règle générale, vous pouvez opter pour les éléments suivants:

  • { static: true }doit être réglé lorsque vous souhaitez accéder à la ViewChilddans ngOnInit.

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

dave0688
la source
2
Remarque: Dans Angular 9, le drapeau statique est défini par défaut sur faux, donc "tous les drapeaux {static: false} peuvent être supprimés en toute sécurité". Documentation: angular.io/guide/static-query-migration
Stevethemacguy
17

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 de l'utiliser static:truesi l'enfant ne dépend d'aucune condition. Si la visibilité de l'élément change, cela static:falsepeut 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.

Sachin Gupta
la source
3
J'ajouterais les motivations officielles derrière cette fonctionnalité github.com/angular/angular/pull/28810
Massimiliano Sartoretto
2

Entré ici parce qu'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 (statiques: false) sont remplies après. En d'autres termes, si un enfant de vue est désormais nul dans ngOnInit après avoir défini static: false, vous devez envisager de passer à static: true ou 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épendantes de directives structurelles, par exemple une référence ViewChild à l'intérieur d'un ngIf, devraient s'exécuter après que le conditionnel de cette directive a été résolu, c'est-à-dire après la détection de changement. Cependant, on peut utiliser en toute sécurité static: true et ainsi résoudre les requêtes avant ngOnInit pour les références non imbriquées. À mon humble avis, ce cas particulier mérite d'être mentionné comme une exception nulle.C'est probablement la première façon de rencontrer cette particularité, comme ce fut le cas pour moi.

corolle
la source
1

afficher l'enfant @angular 5+ token deux arguments ('local reference name', static: false | true)

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

pour savoir la différence entre vrai et faux vérifier cela

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.

Samar Abdallah
la source
0

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 onInithook: Par exemple:

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

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

Si statique est faux, vous n'obtiendrez que la définition dans ngAfterViewInit (), dans ngOnInit (), vous ne serez pas défini.

Tethys Zhang
la source