J'essaie de comprendre la différence entre ng-if
et ng-show
/ng-hide
, mais ils me ressemblent.
Y a-t-il une différence que je devrais garder à l'esprit en choisissant d'utiliser l'un ou l'autre?
La directive ngIf
supprime ou recrée une partie de l'arborescence DOM basée sur une expression. Si l'expression affectée à ngIf
est évaluée à une valeur false, 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 est détruite 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 la portée parente à l'aide de l'héritage du prototype.
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 de 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 à partir 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 directive ngShow
affiche ou masque l'élément HTML donné en fonction de l'expression fournie à l'attribut ngShow
. L'élément est affiché ou masqué en supprimant ou en ajoutant la classe CSS ng-hide
à l'élément. La classe CSS .ng-hide
est prédéfinie dans AngularJS et définit le style d'affichage sur none (à l'aide d'un indicateur !important
).
<!-- 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'expression ngShow
a la valeur false
, la classe CSS ng-hide
est ajoutée à l'attribut class
de l'élément, ce qui la masque. Lorsque true
, la classe CSS ng-hide
est supprimée de l'élément, ce qui fait que cet élément n'apparaît pas masqué.
Peut-être un point intéressant à faire est la différence entre les priorités des deux.
Autant que je sache, la directive ng-if a l'une des plus hautes priorités (sinon la plus haute) de toutes les directives angulaires. Ce qui signifie: il fonctionnera EN PREMIER avant toutes les autres directives moins prioritaires. Le fait qu'il fonctionne en premier signifie que l'élément est effectivement supprimé avant le traitement de toute directive inner . 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’ensemble de l’interface utilisateur est très chargé et contient ng-show et ng-hide. Sans trop entrer dans les détails, j'ai construit un composant générique pouvant être géré à l'aide de la configuration JSON. J'ai donc dû basculer à l'intérieur du modèle. Il y a un ng-repeat présent, et à l'intérieur du ng-repeat, un tableau est présenté, qui contient de nombreux ng-shows, ng-masques et même ng-commutateurs. Ils souhaitaient 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 prend environ 150 ms pour traiter les données, puis Angular mâchonne environ 2 à 3 secondes avant de s'afficher. Le client ne s'est pas plaint, mais j'ai été consterné :-)
Dans mes recherches, je suis tombé sur la directive ng-if. Maintenant, il est peut-être préférable de signaler qu’au moment de la conception de cette interface utilisateur, il n’y avait aucune option. Parce que ng-show et ng-hide avaient des fonctions en elles, qui renvoyaient des booléens, je pouvais facilement les remplacer 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 l'interface utilisateur s'est donc accélérée à 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 quoi que ce soit), mais simplement caché, utilisez ng-show/ng-hide. Dans tous les autres cas, utilisez ng-if.
La directive ng-if
supprime le contenu de la page et ng-show/ng-hide
utilise la propriété CSS display
pour masquer le contenu.
Ceci est utile si vous souhaitez utiliser les pseudo-sélecteurs :first-child
et :last-child
pour styler.
@ EdSpencer est correct. Si vous avez beaucoup d'éléments et que vous utilisez ng-if pour instancier seulement ceux qui sont pertinents, vous économisez des ressources . @ CodeHater est également correct, si vous allez supprimer et afficher un élément très souvent, le masquer au lieu de l'enlever 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 jettera une erreur, mais si je vérifie si elle est nulle, c’est bien. Si je faisais un ng-show, l'erreur se déclencherait quand même.
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 que vous définissez ng-show="false"
pour le masquer, Chrome génère l'erreur suivante lorsque l'utilisateur tente de soumettre le formulaire:
An invalid form control with name='' is not focusable.
La raison en est que le champ de saisie est présent et qu'il est required
mais, étant donné qu'il est caché, Chrome ne peut pas se concentrer sur celui-ci. Cela peut littéralement casser votre code car cette erreur interrompt 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 false, tous les éléments html seront supprimés de DOM. et si la valeur assignée est true, les éléments html seront visibles sur le DOM. Et la portée sera différente de celle du parent. Mais dans le cas de ng-show, il affichera et cachera les éléments en fonction de la valeur assignée. Mais ça reste toujours dans le DOM. Seule la visibilité change selon la valeur assignée.
http://plnkr.co/edit/3G0V9ivUzzc8kpLb1OQn?p=preview
J'espère que cet exemple vous aidera à comprendre les portées . Essayez de donner des valeurs fausses à 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 réalité, la directive ng-if
, contrairement à ng-show
, crée sa propre portée, 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'événement on-click
, la variable show
, de innner/own scope, est modifié, mais ng-if
surveille une autre variable de outer scope avec le même nom; la solution ne fonctionne donc pas. Dans le cas de ng-show
, nous avons la seule variable show
, c’est pourquoi cela fonctionne. Pour corriger la première tentative, nous devrions faire référence à show
à partir de la portée parent/externe via $parent.show
.
ng-if if false supprimera les éléments de 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 est supprimé du DOM et à nouveau lorsqu'il est vrai, il est recréé.
ng-show/ng-hide ne supprime pas les éléments de DOM. Il utilise les styles CSS (.ng-hide) pour masquer/afficher les éléments. Ainsi, vos événements, directives attachés aux enfants ne seront pas perdus.
ng-if crée une étendue enfant, contrairement à ng-show/ng-hide.
ngIf effectue une manipulation sur le DOM en supprimant ou en recréant l'élément.
Alors que ngShow applique une règle CSS pour cacher/montrer des choses.
Dans la plupart des cas (pas toujours) , je résumerais ceci: si vous avez besoin d’un contrôle unique pour afficher/masquer des éléments, utilisez ng-if
, si vous devez afficher/masquer des éléments en fonction des actions de l'écran (comme cocher une case puis afficher la zone de texte, décoché puis masquer la zone de texte, etc.), puis utilisez ng-show
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, l'élément sera créé dans le dom mais avec l'élément ng-hide/ng-show 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.
A noter, une chose qui m'est arrivée maintenant: Ng-show cache le contenu via css, oui, mais cela a entraîné d'étranges problèmes dans div censés être des boutons.
J'avais une carte avec deux boutons en bas et en fonction de l'état actuel, on échange un troisième, exemple de bouton d'édition avec une nouvelle entrée. En utilisant ng-show = false pour cacher celui de gauche (présent en premier dans le fichier), il est arrivé que le bouton suivant se termine avec le bord droit en dehors de la carte . Ng-if corrige cela en n'incluant pas le code du tout . (Il suffit de cocher ici s'il y a des surprises cachées en utilisant ng-if au lieu de ng-show)