J'essaie de comprendre la différence entre ng-if
et ng-show
/ ng-hide
, mais ils me semblent identiques.
Y a-t-il une différence que je dois garder à l'esprit en choisissant d'utiliser l'un ou l'autre?
J'essaie de comprendre la différence entre ng-if
et ng-show
/ ng-hide
, mais ils me semblent identiques.
Y a-t-il une différence que je dois garder à l'esprit en choisissant d'utiliser l'un ou l'autre?
Réponses:
La ngIf
directive supprime ou recrée une partie de l'arborescence DOM en fonction d'une expression. Si l'expression affectée à ngIf
évalue une valeur fausse, l'élément est supprimé du DOM, sinon un clone de l'élément est réinséré dans le DOM.
<!-- when $scope.myValue is truthy (element is restored) -->
<div ng-if="1"></div>
<!-- when $scope.myValue is falsy (element is removed) -->
<div ng-if="0"></div>
Lorsqu'un élément est supprimé à l'aide de ngIf
sa portée, il est détruit et une nouvelle portée est créée lors de la restauration de l'élément. La portée créée dans ngIf
hérite de sa portée parent à l'aide de l'héritage prototypique.
Si ngModel
est utilisé dans ngIf
pour se lier à une primitive JavaScript définie dans la portée parent, toute modification apportée à la variable dans la portée enfant n'affectera pas la valeur dans la portée parent, par exemple
<input type="text" ng-model="data">
<div ng-if="true">
<input type="text" ng-model="data">
</div>
Pour contourner cette situation et mettre à jour le modèle dans la portée parent depuis l'intérieur de la portée enfant, utilisez un objet:
<input type="text" ng-model="data.input">
<div ng-if="true">
<input type="text" ng-model="data.input">
</div>
Ou, $parent
variable pour référencer l'objet de portée parent:
<input type="text" ng-model="data">
<div ng-if="true">
<input type="text" ng-model="$parent.data">
</div>
La ngShow
directive affiche ou masque l'élément HTML donné en fonction de l'expression fournie à l' ngShow
attribut. L'élément est affiché ou masqué en supprimant ou en ajoutant la ng-hide
classe CSS à l'élément. La .ng-hide
classe CSS est prédéfinie dans AngularJS et définit le style d'affichage sur aucun (à l'aide d'un !important
indicateur).
<!-- when $scope.myValue is truthy (element is visible) -->
<div ng-show="1"></div>
<!-- when $scope.myValue is falsy (element is hidden) -->
<div ng-show="0" class="ng-hide"></div>
Lorsque l' ngShow
expression est évaluée, false
la ng-hide
classe CSS est ajoutée à l' class
attribut de l'élément, ce qui le rend masqué. Lorsque true
, la ng-hide
classe CSS est supprimée de l'élément, ce qui ne semble pas masqué.
data.input
cela fonctionne ... mais data
seul dans le modèle ne fonctionne pas. @CodeHater
ngIf
crée une nouvelle étendue, donc en regardant l'exemple ci-dessus l'imbriqué ngModel
créerait un nouveau data
modèle même si un modèle du même nom existe dans l'étendue parent. Mais lorsque vous utilisez une notation par points, vous demandez à JS de rechercher la chaîne de prototypes de l'oscilloscope. Donc, s'il ne trouve pas la valeur dans la portée actuelle, il essaiera de la rechercher dans la portée parent et ainsi de suite. Peu d' autres directives qui créent une portée différente sont ngInclude
, ngRepeat
. J'espère que c'est clair maintenant. :)
Peut-être un point intéressant à faire est la différence entre les priorités entre les deux.
Pour autant que je sache, la directive ng-if a l'une des priorités les plus élevées (sinon la plus élevée) de toutes les directives angulaires. Ce qui signifie: il s'exécutera en PREMIER avant toutes les autres directives, de moindre priorité. Le fait qu'il s'exécute en PREMIER signifie que l'élément est supprimé avant le traitement des directives internes . Ou du moins: c'est ce que j'en fais.
J'ai observé et utilisé cela dans l'interface utilisateur que je construis pour mon client actuel. L'interface utilisateur entière est assez compacte, et il y avait ng-show et ng-hide partout. Pour ne pas entrer dans trop de détails, mais j'ai construit un composant générique, qui pourrait être géré à l'aide de la configuration JSON, j'ai donc dû faire quelques changements à l'intérieur du modèle. Il y a un ng-repeat présent, et à l'intérieur du ng-repeat, un tableau est affiché, qui a beaucoup de ng-shows, ng-hides et même ng-switches présents. Ils voulaient afficher au moins 50 répétitions dans la liste, ce qui entraînerait la résolution de plus ou moins 1500-2000 directives. J'ai vérifié le code, et le backend Java + JS personnalisé sur le front prendrait environ 150 ms pour traiter les données, puis Angular mâcherait environ 2-3 secondes dessus, avant de s'afficher. Le client ne s'est pas plaint, mais j'ai été consterné :-)
Dans ma recherche, je suis tombé sur la directive ng-if. Maintenant, il vaut peut-être mieux souligner qu'au moment de concevoir cette interface utilisateur, il n'y avait pas de ng-if disponible. Parce que le ng-show et le ng-hide avaient des fonctions en eux, qui renvoyaient des booléens, je pouvais facilement les remplacer tous par ng-if. Ce faisant, toutes les directives internes ne semblaient plus être évaluées. Cela signifiait que je suis revenu à environ un tiers de toutes les directives en cours d'évaluation, et donc, l'interface utilisateur a accéléré jusqu'à environ 500 ms - 1 seconde de temps de chargement. (Je n'ai aucun moyen de déterminer les secondes exactes)
Remarque: le fait que les directives ne soient pas évaluées est une supposition éclairée de ce qui se passe en dessous.
Donc, à mon avis: si vous avez besoin que l'élément soit présent sur la page (c'est-à-dire: pour vérifier l'élément, ou autre), mais simplement être caché, utilisez ng-show / ng-hide. Dans tous les autres cas, utilisez ng-if.
La ng-if
directive supprime le contenu de la page et ng-show/ng-hide
utilise la display
propriété CSS pour masquer le contenu.
Ceci est utile dans le cas où vous souhaitez utiliser :first-child
et :last-child
sélecteurs de pseudo au style.
:first-child
et :last-child
developer.mozilla.org/en-US/docs/Web/CSS/:first-child developer.mozilla.org/en-US/docs/Web/CSS/:last-child
@EdSpencer est correct. Si vous avez beaucoup d'éléments et que vous utilisez ng-if pour instancier uniquement les éléments pertinents, vous économisez des ressources. @CodeHater est également quelque peu correct, si vous souhaitez supprimer et afficher un élément très souvent, le cacher au lieu de le supprimer pourrait améliorer les performances.
Le principal cas d'utilisation que je trouve pour ng-if est qu'il me permet de valider et d'éliminer proprement un élément si le contenu est illégal. Par exemple, je pourrais faire référence à une variable de nom d'image nulle et cela générera une erreur, mais si je négocie et vérifie si elle est nulle, tout va bien. Si je faisais un ng-show, l'erreur se déclencherait toujours.
Une chose importante à noter à propos de ng-if et ng-show est que lorsque vous utilisez des contrôles de formulaire, il est préférable d'utiliser ng-if
car il supprime complètement l'élément du dom.
Cette différence est importante car si vous créez un champ de saisie avec required="true"
puis définissez-le ng-show="false"
pour le masquer, Chrome générera l'erreur suivante lorsque l'utilisateur tentera de soumettre le formulaire:
An invalid form control with name='' is not focusable.
La raison étant que le champ de saisie est présent et il l'est required
mais puisqu'il est caché, Chrome ne peut pas se concentrer dessus. Cela peut littéralement casser votre code car cette erreur arrête l'exécution du script. Donc sois prudent!
@Gajus Kuizinas et @CodeHater sont corrects. Ici, je donne juste un exemple. Pendant que nous travaillons avec ng-if, si la valeur assignée est fausse, tous les éléments html seront supprimés du DOM. et si la valeur assignée est vraie, alors les éléments html seront visibles sur le DOM. Et la portée sera différente de la portée parent. Mais en cas de ng-show, il affichera et masquera simplement les éléments en fonction de la valeur assignée. Mais il reste toujours dans le DOM. Seule la visibilité change selon la valeur attribuée.
http://plnkr.co/edit/3G0V9ivUzzc8kpLb1OQn?p=preview
J'espère que cet exemple vous aidera à comprendre les portées. Essayez de donner de fausses valeurs à ng-show et ng-if et vérifiez le DOM dans la console. Essayez d'entrer les valeurs dans les zones de saisie et observez la différence.
<!DOCTYPE html>
<input type="text" ng-model="data">
<div ng-show="true">
<br/>ng-show=true :: <br/><input type="text" ng-model="data">
</div>
<div ng-if="true">
<br/>ng-if=true :: <br/><input type="text" ng-model="data">
</div>
{{data}}
En fait, cette ng-if
directive, contrairement à elle ng-show
, crée son propre champ d’application, conduit à une différence pratique intéressante:
angular.module('app', []).controller('ctrl', function($scope){
$scope.delete = function(array, item){
array.splice(array.indexOf(item), 1);
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app' ng-controller='ctrl'>
<h4>ng-if:</h4>
<ul ng-init='arr1 = [1,2,3]'>
<li ng-repeat='x in arr1'>
{{show}}
<button ng-if='!show' ng-click='show=!show'>Delete {{show}}</button>
<button ng-if='show' ng-click='delete(arr1, x)'>Yes {{show}}</button>
<button ng-if='show' ng-click='show=!show'>No</button>
</li>
</ul>
<h4>ng-show:</h4>
<ul ng-init='arr2 = [1,2,3]'>
<li ng-repeat='x in arr2'>
{{show}}
<button ng-show='!show' ng-click='show=!show'>Delete {{show}}</button>
<button ng-show='show' ng-click='delete(arr2, x)'>Yes {{show}}</button>
<button ng-show='show' ng-click='show=!show'>No</button>
</li>
</ul>
<h4>ng-if with $parent:</h4>
<ul ng-init='arr3 = [1,2,3]'>
<li ng-repeat='item in arr3'>
{{show}}
<button ng-if='!show' ng-click='$parent.show=!$parent.show'>Delete {{$parent.show}}</button>
<button ng-if='show' ng-click='delete(arr3, x)'>Yes {{$parent.show}}</button>
<button ng-if='show' ng-click='$parent.show=!$parent.show'>No</button>
</li>
</ul>
</div>
Dans la première liste, l' on-click
événement, la show
variable, de portée interne / propre , est modifié, mais ng-if
surveille une autre variable de portée externe avec le même nom, donc la solution ne fonctionne pas. Au cas où ng-show
nous avons la seule show
variable, c'est pourquoi cela fonctionne. Pour corriger la première tentative, nous devons faire référence à show
partir de la portée parent / externe via $parent.show
.
ng-if if false supprimera les éléments du DOM. Cela signifie que tous vos événements, les directives attachées à ces éléments seront perdus. Par exemple, ng-cliquez sur l'un des éléments enfants, lorsque ng-if est évalué à false, cet élément sera supprimé du DOM et à nouveau lorsqu'il est vrai, il est recréé.
ng-show / ng-hide ne supprime pas les éléments du DOM. Il utilise des styles CSS (.ng-hide) pour masquer / afficher les éléments. De cette façon, vos événements, les directives qui ont été attachées aux enfants ne seront pas perdus.
ng-if crée une portée enfant, contrairement à ng-show / ng-hide.
ng-show et ng-hide fonctionnent de manière opposée. Mais la différence entre ng-hide ou ng-show avec ng-if est, si nous utilisons ng-if, alors l'élément sera créé dans le dom mais avec ng-hide / ng-show, l'élément sera complètement masqué.
ng-show=true/ng-hide=false:
Element will be displayed
ng-show=false/ng-hide=true:
element will be hidden
ng-if =true
element will be created
ng-if= false
element will be created in the dom.
À noter, une chose qui m'est arrivée maintenant: ng-show masque le contenu via css, oui, mais cela a entraîné d'étranges problèmes dans les divs censés être des boutons.
J'avais une carte avec deux boutons en bas et en fonction de l'état réel, elle est échangée avec un troisième bouton d'édition d'exemple avec une nouvelle entrée. En utilisant ng-show = false pour masquer celui de gauche (présent en premier dans le fichier), il est arrivé que le bouton suivant se retrouve avec la bordure droite à l'extérieur de la carte. ng-if corrige cela en n'incluant pas du tout le code. (Juste vérifié ici s'il y a des surprises cachées en utilisant ng-if au lieu de ng-show)
ngIf effectue une manipulation sur le DOM en supprimant ou recréant l'élément.
Alors que ngShow applique des règles CSS pour masquer / afficher les choses.
Pour la plupart des cas (pas toujours) , je résumerais cela comme: si vous avez besoin d'une vérification unique pour afficher / masquer les choses, utilisez ng-if
, si vous devez afficher / masquer les choses en fonction des actions de l'utilisateur à l'écran (comme vérifié une case à cocher puis afficher la zone de texte, décoché puis masquer la zone de texte, etc.), puis utiliserng-show
Une différence intéressante entre ng-if et ng-show est:
SÉCURITÉ
Les éléments DOM présents dans le bloc ng-if ne seront pas rendus en cas de valeur false
où comme dans le cas de ng-show, l'utilisateur peut ouvrir votre fenêtre Inspect Element et définir sa valeur sur TRUE.
Et avec un whoop, tout le contenu qui devait être caché s'affiche, ce qui constitue une faille de sécurité. :)
ng-if
le modèle, ajouté parng-model
, n'existe plus.