Quand privilégier ng-if vs ng-show / ng-hide?

Réponses:

703

Dépend de votre cas d'utilisation mais pour résumer la différence:

  1. ng-ifsupprimera les éléments du DOM. Cela signifie que tous vos gestionnaires ou tout autre élément attaché à ces éléments seront perdus. Par exemple, si vous liez un gestionnaire de clics à l'un des éléments enfants, lorsqu'il est ng-ifévalué à faux, cet élément sera supprimé du DOM et votre gestionnaire de clics ne fonctionnera plus, même après une ng-ifévaluation ultérieure à true et l'affichage de l'élément. Vous devrez rattacher le gestionnaire.
  2. ng-show/ng-hidene supprime pas les éléments du DOM. Il utilise des styles CSS pour masquer / afficher les éléments (remarque: vous devrez peut-être ajouter vos propres classes). De cette façon, vos gestionnaires attachés aux enfants ne seront pas perdus.
  3. ng-ifcrée une portée enfant ng-show/ng-hidesans

Les éléments qui ne sont pas dans le DOM ont moins d'impact sur les performances et votre application Web peut sembler plus rapide lors de l'utilisation ng-ifpar rapport à ng-show/ng-hide. D'après mon expérience, la différence est négligeable. Des animations sont possibles lors de l'utilisation des deux ng-show/ng-hideet ng-if, avec des exemples pour les deux dans la documentation Angular.

En fin de compte, la question à laquelle vous devez répondre est de savoir si vous pouvez supprimer l'élément du DOM ou non?

markovuksanovic
la source
19
Vous pouvez utiliser des animations CSS3 avec ng-if. Vérifiez le paragraphe Animations et l'exemple dans la documentation . Également avec ng-hide/ng-showles sélecteurs CSS comme :first-childou :nth-childne fonctionnera pas correctement car les éléments cachés seront également comptés.
Łukasz Wojciechowski
4
Le service d'animation dans angular.dart est relativement nouveau. Au moment de la rédaction de ce document, il n'était pas disponible.
markovuksanovic
44
Votre premier point n'est pas un problème si vous utilisez des directives (comme ng-click) pour lier les gestionnaires, comme vous devriez l'être.
Kevin C.
9
En outre, ng-ifcrée une nouvelle portée alors que ce ng-shown'est pas le cas.
martin
8
Il convient également de mentionner que l'ajout et la suppression d'éléments du DOM peuvent entraîner des coûts de performances élevés s'ils sont effectués fréquemment.
Kevin C.
130

Voir ici pour un CodePen qui montre la différence dans le fonctionnement de ng-if / ng-show, DOM-sage.

@markovuksanovic a bien répondu à la question. Mais je viens à partir d' un autre point de vue: je toujours utiliser ng-ifet obtenir ces éléments de DOM, à moins que :

  1. pour une raison quelconque, vous avez besoin des liaisons de données et des $watch-es sur vos éléments pour rester actifs pendant qu'ils sont invisibles. Les formulaires peuvent être un bon cas pour cela, si vous voulez pouvoir vérifier la validité des entrées qui ne sont pas actuellement visibles, afin de déterminer si l'ensemble du formulaire est valide.
  2. Vous utilisez une logique d'état très élaborée avec des gestionnaires d'événements conditionnels, comme mentionné ci-dessus. Cela dit , si vous vous trouvez à attacher et à détacher manuellement des gestionnaires, de sorte que vous perdez un état important lorsque vous utilisez ng-if, demandez-vous si cet état serait mieux représenté dans un modèle de données, et les gestionnaires appliqués conditionnellement par des directives à chaque fois l'élément est rendu. Autrement dit, la présence / absence de gestionnaires est une forme de données d'état. Obtenez ces données du DOM et dans un modèle. La présence / absence des gestionnaires doit être déterminée par les données et donc facile à recréer.

Angular est très bien écrit. C'est rapide, vu ce qu'il fait. Mais ce qu'il fait, c'est tout un tas de magie qui rend les choses difficiles (comme la liaison de données bidirectionnelle) très simples. Rendre toutes ces choses faciles implique des frais généraux de performance. Vous pourriez être choqué de réaliser combien de centaines ou de milliers de fois une fonction de définition est évaluée pendant le $digestcycle sur un morceau de DOM que personne ne regarde même. Et puis vous vous rendez compte que vous avez des dizaines ou des centaines d'éléments invisibles faisant tous la même chose ...

Les bureaux peuvent en effet être suffisamment puissants pour rendre la plupart des problèmes de vitesse d'exécution JS sans objet. Mais si vous développez pour mobile, utiliser ng-if chaque fois que cela est humainement possible devrait être une évidence. La vitesse JS compte toujours sur les processeurs mobiles. L'utilisation de ng-if est un moyen très simple d'obtenir une optimisation potentiellement significative à un coût très, très faible.

XML
la source
6
Très bel ajout à la réponse ci-dessus. Donné avec un bon contexte, ce qui aide également à la prise de décision. Merci.
Sean
1
ng-showpeut être utile lorsque vous disposez, par exemple, d'onglets contenant chacun beaucoup de contenu dont le rendu est long. Après le premier rendu, le déplacement entre les onglets sera instantané, alors ng-ifqu'il faudrait un nouveau rendu, des événements de liaison, etc. L'inconvénient, comme vous le dites, est de créer des montres s'exécutant en arrière-plan. Angular a désespérément besoinng-ifshowwatch
poshest
53

Selon mon expérience:

1) Si votre page a une bascule qui utilise ng-if / ng-show pour afficher / masquer quelque chose, ng-if entraîne plus de retard dans le navigateur (plus lent). Par exemple: si vous avez un bouton utilisé pour basculer entre deux vues, ng-show semble être plus rapide.

2) ng-if créera / détruira la portée quand il évaluera à vrai / faux. Si vous avez un contrôleur attaché au ng-if, ce code de contrôleur sera exécuté à chaque fois que le ng-if aura la valeur true. Si vous utilisez ng-show, le code du contrôleur n'est exécuté qu'une seule fois. Donc, si vous avez un bouton qui bascule entre plusieurs vues, l'utilisation de ng-if et ng-show ferait une énorme différence dans la façon dont vous écrivez le code de votre contrôleur.

Yi Z
la source
5
C'est une énorme vérité! ng-if ne rend pas nécessairement votre interface plus rapide. Cela dépend de vos besoins. En fait, cela pourrait faire l'inverse si vous utilisez dans une mauvaise situation.
Thiago C. S Ventura du
1
Mais selon moi, ng-if ne rend pas sur DOM, il est donc rapide par rapport à ng-show / hide. ai-je tort pls permettez-moi de corriger à ce point.
Pardeep Jain
1
ng-if serait plus rapide s'il est évalué à faux, car, comme vous le dites, rien n'a besoin d'être inséré dans le DOM. Mais, si c'est vrai, vous avez une surcharge d'insérer l'élément - peut-être assez compliqué - dans le DOM.
Mawg dit réintégrer Monica le
"2) ng-if créera / détruira la portée quand il évaluera à vrai / faux. Si vous avez un contrôleur attaché au ng-if, ce code de contrôleur sera exécuté chaque fois que"
The Red Pea
35

La réponse n'est pas simple:

Cela dépend des machines cibles (mobile vs desktop), cela dépend de la nature de vos données, du navigateur, du système d'exploitation, du matériel sur lequel il fonctionne ... vous aurez besoin de comparer si vous voulez vraiment savoir.

C'est principalement un problème de mémoire vs de calcul ... comme avec la plupart des problèmes de performances, la différence peut devenir significative avec des éléments répétés (n) comme des listes, en particulier lorsqu'ils sont imbriqués (nxn, ou pire) et aussi quel type de calculs vous exécutez à l'intérieur de ces éléments :

  • ng-show : si ces éléments facultatifs sont souvent présents (denses), comme disons 90% du temps, il peut être plus rapide de les avoir prêts et de les afficher / masquer uniquement, surtout si leur contenu est bon marché (juste du texte brut, rien pour calculer ou charger). Cela consomme de la mémoire car il remplit le DOM d'éléments cachés, mais simplement afficher / masquer quelque chose qui existe déjà est susceptible d'être une opération bon marché pour le navigateur.

  • ng-if : Si au contraire les éléments ne sont probablement pas affichés (rares), il suffit de les construire et de les détruire en temps réel, surtout si leur contenu est cher à obtenir (calculs / triés / filtrés, images, images générées). Ceci est idéal pour les éléments rares ou `` à la demande '', il économise de la mémoire en termes de non remplissage du DOM mais peut coûter beaucoup de calcul (création / destruction d'éléments) et de bande passante (obtention de contenu distant). Cela dépend également de la quantité que vous calculez dans la vue (filtrage / tri) par rapport à ce que vous avez déjà dans le modèle (données pré-triées / pré-filtrées).

Christophe Roussy
la source
2
Autres réponses pour des faits techniques. Celui-ci pour la sagesse. Vous avez clairement construit des applications angulaires non triviales monsieur! +1
poshest
Ce problème dépasse l'angulaire, c'est un problème fondamental en informatique, il y a un point à partir duquel une méthode est plus efficace que l'autre. Habituellement, cela peut être trouvé grâce à une analyse comparative. Vous pouvez donc même basculer d'une méthode à l'autre en fonction du nombre d'articles ... Sujet similaire: math.stackexchange.com/questions/1632739/…
Christophe Roussy
12

Une remarque importante:

ngIf (contrairement à ngShow) crée généralement des étendues enfants qui peuvent produire des résultats inattendus.

J'ai eu un problème lié à cela et j'ai passé BEAUCOUP de temps à comprendre ce qui se passait.

(Ma directive écrivait ses valeurs de modèle dans la mauvaise portée.)

Donc, pour sauver vos cheveux, utilisez simplement ngShow à moins que vous ne couriez trop lentement.

La différence de performance est à peine perceptible de toute façon et je ne sais pas encore qui est en faveur sans test ...

user2173353
la source
8
L'utilisation $parent.scopevarde liaisons de données dans un ngIf corrigera des problèmes tels que les portées enfants lors de l'utilisation de ngIf
meconroy
2
Ce n'est pas entièrement vrai (le commentaire original de @ user2173353, c'est-à-dire). Si vous vous en tenez aux bonnes pratiques, vous n'aurez pas de problèmes. C'est une règle assez basique: "s'il n'y a pas de point, vous vous trompez". Voir ici pour une démonstration de son fonctionnement: bit.ly/1SPv4wL . Une autre grande référence (voir erreur # 2): bit.ly/1QfFeWd > (Ma directive écrivait ses valeurs de modèle dans la mauvaise portée.) Ceci est le résultat de ne pas s'en tenir à la pratique ci-dessus.
piotr.d
1
@ piotr.d Vous avez raison, mais ce n'est pas quelque chose sur lequel un débutant devra peut-être se concentrer et il existe une autre meilleure pratique qui dit qu'il vaut mieux laisser les améliorations de performances pour la fin (en particulier les améliorations de performances qui peuvent ne pas être des améliorations dans la réalité ). J'ai vu des gens mettre ngIfpartout croyant que cela améliorerait les performances. Ce n'est tout simplement pas vrai et on ne peut pas dire lequel est le meilleur, ngIfou ngShow, sans test ou analyse approfondie dans le cas particulier. Donc, je recommande toujours d'oublier ngIfjusqu'à ce que quelqu'un voit de mauvaises performances ou sache ce qu'il fait
user2173353
2
Bon point. Mais l'utilisation de controllerAs en fait un non-problème. Voir, par exemple, le point de vue de John Papa sur controllerAs et vm .
jsruok
4

ng-if sur ng-include et sur ng-controller aura un impact important sur ng-include, il ne chargera pas le partiel requis et ne traitera pas à moins que flag soit vrai sur ng-controller il ne chargera pas le contrôleur à moins que flag ne soit true mais le problème est quand un drapeau devient faux dans ng-si il se retire du DOM quand le drapeau revient vrai il rechargera le DOM dans ce cas ng-show est meilleur, pour une fois montrer ng-if est meilleur

Saad Ahmed
la source
4

Si vous utilisez ng-show or ng-hidele contenu (par exemple, les miniatures du serveur) sera chargé quelle que soit la valeur de l'expression mais sera affiché en fonction de la valeur de l'expression.

Si vous utilisez, ng-ifle contenu ne sera chargé que si l'expression du ng-if est jugée véridique.

L'utilisation de ng-if est une bonne idée dans une situation où vous allez charger des données ou des images à partir du serveur et les afficher uniquement en fonction de l'interaction des utilisateurs. De cette façon, le chargement de votre page ne sera pas bloqué par des tâches intensives inutiles.

appdroid
la source
Ceci est particulièrement utile car la plupart des navigateurs chargent des images même si le CSS cache leurs conteneurs DOM. Ils recherchent généralement l' srcattribut de la imgbalise, lorsqu'elle est présente, elle est chargée!
Christophe Roussy