Quelle est la meilleure façon d'appliquer conditionnellement une classe?


1183

Disons que vous avez un tableau qui est rendu dans un ulavec un lipour chaque élément et une propriété sur le contrôleur appelé selectedIndex. Quelle serait la meilleure façon d'ajouter une classe à lil'index selectedIndexdans AngularJS?

Je suis en train de dupliquer (à la main) le licode et d'ajouter la classe à l'une des libalises et d'utiliser ng-showet ng-hided'afficher une seule lipar index.


2
Les réponses à cette question montrent qu'il y a plus dans le modèle que {{varname}}. Où puis-je trouver de la documentation sur ce qu'il y a de plus dans les modèles, comme l'opérateur ternaire sous deux formes différentes? docs.angularjs.org/guide/templates ne semble pas expliquer ce que les modèles offrent en termes de conditions, etc. à part {{varname.fieldname}}.
Christos Hayward

c'est tellement utile pour moi j'espère que cela fonctionnera pour vous tech-blog.maddyzone.com/javascript/…
Rituraj ratan

Réponses:


1384

Si vous ne voulez pas mettre les noms de classe CSS dans Controller comme je le fais, voici une vieille astuce que j'utilise depuis les jours antérieurs à la v1. Nous pouvons écrire une expression qui évalue directement un nom de classe sélectionné , aucune directive personnalisée n'est nécessaire:

ng:class="{true:'selected', false:''}[$index==selectedIndex]"

Veuillez noter l'ancienne syntaxe avec deux points.

Il existe également une nouvelle meilleure façon d'appliquer les classes de manière conditionnelle, comme:

ng-class="{selected: $index==selectedIndex}"

Angular prend désormais en charge les expressions qui renvoient un objet. Chaque propriété (nom) de cet objet est désormais considérée comme un nom de classe et est appliquée en fonction de sa valeur.

Cependant, ces façons ne sont pas fonctionnellement égales. Voici un exemple:

ng-class="{admin:'enabled', moderator:'disabled', '':'hidden'}[user.role]"

Nous pourrions donc réutiliser les classes CSS existantes en mappant fondamentalement une propriété de modèle à un nom de classe et en même temps garder les classes CSS hors du code du contrôleur.


33
OP, c'est peut-être la pire façon d'exprimer l'opérateur ternaire que j'ai jamais vu. Avez-vous réfléchi ($index==selectedIndex) ? 'selected' : ''?
Malvolio

17
@Malvolio AFAIR, l'opérateur ternaire ne fonctionnait pas dans les expressions angulaires en v0.9.x. C'est plus ou moins un interrupteur.
orcun

36
ng-class (à partir du 19/01/2012) prend désormais en charge une expression qui doit évaluer soit 1) une chaîne de noms de classe délimités par des espaces, soit 2) et un tableau de noms de classe, ou 3) une carte / un objet de classe noms en valeurs booléennes. Donc, en utilisant 3): ng-class = "{selected: $ index == selectedIndex}"
Mark Rajcok

2
Merci @Mark, BTW maintenant que j'ai vérifié, je peux dire que cette méthode fonctionne en v1. C'est toujours utile dans certains cas. Notez que les noms de propriété d'objet (clés) ne sont pas nécessairement vrais ou faux, il peut s'agir de tout ce que vous pourriez vouloir mapper à un nom de classe.
orcun

6
Je veux juste ajouter, j'avais un problème parce que j'utilisais la syntaxe comme {classname: '$index === selectedIndex'} et ça ne fonctionnait pas. Quand j'ai tout rassemblé et utilisé == au lieu de === cela a fonctionné. {classname: '$index==selectedIndex'}
Lucas

437

ng-class prend en charge une expression qui doit être évaluée à

  1. Une chaîne de noms de classe délimités par des espaces, ou
  2. Un tableau de noms de classe, ou
  3. Un mappage / objet des noms de classe aux valeurs booléennes.

Donc, en utilisant le formulaire 3), nous pouvons simplement écrire

ng-class="{'selected': $index==selectedIndex}"

Voir aussi Comment appliquer conditionnellement des styles CSS dans AngularJS? pour une réponse plus large.


Mise à jour : Angular 1.1.5 a ajouté la prise en charge d'un opérateur ternaire , donc si cette construction vous est plus familière:

ng-class="($index==selectedIndex) ? 'selected' : ''"

2
+1 pour les opérateurs ternaires (et j'en ai besoin en ce moment) mais 1.1. * Est une 'version instable' où l'API est sujette à changement sans préavis - au moment de la saisie. 1.0. * Est stable, donc je serais plus à l'aise avec cela pour un projet qui sera déployé la semaine prochaine pendant 6 mois.
Dave Everitt

1
ng-class="{'selected': $index==selectedIndex}"travaille pour moi
knuhol

160

Ma méthode préférée utilise l'expression ternaire.

ng-class="condition ? 'trueClass' : 'falseClass'"

Remarque: Si vous utilisez une ancienne version d'Angular, vous devez l'utiliser à la place,

ng-class="condition && 'trueClass' || 'falseClass'"

2
Cela m'a aidé à écrire cette expression: ng-class="property.name=='timestamp' ? 'property-timestamp' : 'property-'+{{$index}}". Impossible de trouver un autre moyen.
2015

Je ne vois vraiment pas pourquoi mon booléen de portée modalFlag ne se met pas à jour - ng-class = "{'fermé': modalFlag, 'ouvert':! ModalFlag}" J'essaie d'ajouter soit fermé soit ouvert selon la variable de portée / booléen - si quelqu'un peut m'aider, je vous en serais très reconnaissant - merci.
atterri

Cela a été introduit en tant que version 1.5. github.com/angular/angular.js/commit/…
Mubashir Koul

55

J'ajouterai à cela, car certaines de ces réponses semblent obsolètes. Voici comment je le fais:

<class="ng-class:isSelected">

Où 'isSelected' est une variable javascript définie dans le contrôleur angulaire de portée.


Pour répondre plus précisément à votre question, voici comment vous pouvez générer une liste avec cela:

HTML

<div ng-controller="ListCtrl">  
    <li class="ng-class:item.isSelected" ng-repeat="item in list">   
       {{item.name}}
    </li>  
</div>


JS

function ListCtrl($scope) {    
    $scope.list = [  
        {"name": "Item 1", "isSelected": "active"},  
        {"name": "Item 2", "isSelected": ""}
    ]
}


Voir: http://jsfiddle.net/tTfWM/

Voir: http://docs.angularjs.org/api/ng.directive:ngClass


Quelles sont les différences entre class = "ng-class: item.isSelected" et ng-class = "item.isSelected"
zloctb

Vous êtes curieux de savoir si vous utilisez ng-class:classNamesimplement class="{{className}}"?
Roi

48

Voici une solution beaucoup plus simple:

function MyControl($scope){
    $scope.values = ["a","b","c","d","e","f"];
    $scope.selectedIndex = -1;
    
    $scope.toggleSelect = function(ind){
        if( ind === $scope.selectedIndex ){
            $scope.selectedIndex = -1;
        } else{
            $scope.selectedIndex = ind;
        }
    }
    
    $scope.getClass = function(ind){
        if( ind === $scope.selectedIndex ){
            return "selected";
        } else{
            return "";
        }
    }
       
    $scope.getButtonLabel = function(ind){
        if( ind === $scope.selectedIndex ){
            return "Deselect";
        } else{
            return "Select";
        }
    }
}
.selected {
    color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
<div ng-app ng-controller="MyControl">
    <ul>
        <li ng-class="getClass($index)" ng-repeat="value in values" >{{value}} <button ng-click="toggleSelect($index)">{{getButtonLabel($index)}}</button></li>
    </ul>
    <p>Selected: {{selectedIndex}}</p>
</div>


74
Je recommande fortement de garder votre contrôleur à l'abri des trucs CSS. C'est un chemin que vous ne voulez pas emprunter.
leviathan

1
Les noms de classe appartiennent au modèle
Casey

5
À un moment donné, jsfiddle peut manquer de payer ses factures, ou choisir de déménager dans un autre domaine, ou les personnes responsables sont tuées par un bus (voir aussi Bus Factor). Puis-je vous demander d'expliquer ce que fait ce violon dans votre réponse? Ceci est également canonique en cas de débordement de pile.
Sebastian Mach

27

J'ai récemment rencontré un problème similaire et j'ai décidé de créer un filtre conditionnel:

  angular.module('myFilters', []).
    /**
     * "if" filter
     * Simple filter useful for conditionally applying CSS classes and decouple
     * view from controller 
     */
    filter('if', function() {
      return function(input, value) {
        if (typeof(input) === 'string') {
          input = [input, ''];
        }
        return value? input[0] : input[1];
      };
    });

Il prend un seul argument, qui est soit un tableau à 2 éléments ou une chaîne, qui est transformé en un tableau auquel est ajoutée une chaîne vide comme deuxième élément:

<li ng-repeat="item in products | filter:search | orderBy:orderProp |
  page:pageNum:pageLength" ng-class="'opened'|if:isOpen(item)">
  ...
</li>

1
moi à Je viens de créer par exemple un filtre yesNo () retournant les classes 'yes' ou 'no' selon une valeur booléenne 1 o 0:filter('yesNo', function() { return function(input) { // info('yesNo('+ input +')'); switch(input){ case '1': return ' yes '; break; default: return ' no '; break; } } });
svassr

1
ng-class peut gérer une carte / un objet de noms de classe en valeurs booléennes, vous pouvez donc simplement écrire ce qui suit: ng-class = "{yes: some_boolean_expression, no: some_other_boolean_expression}" Par exemple, ng-class = "{yes: input , no
:!

21

Si vous voulez aller au-delà de l'évaluation binaire et garder votre CSS hors de votre contrôleur, vous pouvez implémenter un simple filtre qui évalue l'entrée par rapport à un objet de carte:

angular.module('myApp.filters, [])
  .filter('switch', function () { 
      return function (input, map) {
          return map[input] || '';
      }; 
  });

Cela vous permet d'écrire votre balisage comme ceci:

<div ng-class="muppets.star|switch:{'Kermit':'green', 'Miss Piggy': 'pink', 'Animal': 'loud'}">
    ...
</div>

Salut @Joe, des idées sur la façon de gérer les valeurs nulles? Si je passe null dans l'entrée, il ne
mappera

1
@ user1191559 - vous pouvez ajouter un élément 'par défaut' à la carte, puis renvoyer cette valeur si 'entrée' est nulle.
Joe Steele

17

Ce que j'ai fait récemment, c'était de faire ceci:

<input type="password"  placeholder="Enter your password"
ng-class="{true: 'form-control isActive', false: 'isNotActive'}[isShowing]">

La isShowingvaleur est une valeur qui se trouve sur mon contrôleur qui est basculée d'un simple clic sur un bouton et les parties entre les parenthèses simples sont des classes que j'ai créées dans mon fichier css.

EDIT: Je voudrais également ajouter que codeschool.com a un cours gratuit parrainé par google sur AngularJS qui couvre tous ces trucs, puis certains. Il n'est pas nécessaire de payer quoi que ce soit, il suffit d'ouvrir un compte et de commencer! Bonne chance à tous!


Pourriez-vous fournir un violon ou plus de code ici? Y a-t-il alors isShowingune matrice dans le contrôleur?
Kyle Pennell

Je suppose que c'est un booléen
Mirko

15

L'opérateur ternaire vient d'être ajouté à l'analyseur angulaire en 1.1.5 .

Donc, la façon la plus simple de le faire est maintenant:

ng:class="($index==selectedIndex)? 'selected' : ''"

En outre: class="otherClass ng-class:($index==selectedIndex)? 'selected' : '';".
peter

11

On peut faire une fonction pour gérer la classe de retour avec condition

entrez la description de l'image ici

<script>
    angular.module('myapp', [])
            .controller('ExampleController', ['$scope', function ($scope) {
                $scope.MyColors = ['It is Red', 'It is Yellow', 'It is Blue', 'It is Green', 'It is Gray'];
                $scope.getClass = function (strValue) {
                    switch(strValue) {
                        case "It is Red":return "Red";break;
                        case "It is Yellow":return "Yellow";break;
                        case "It is Blue":return "Blue";break;
                        case "It is Green":return "Green";break;
                        case "It is Gray":return "Gray";break;
                    }
                }
        }]);
</script>

Et alors

<body ng-app="myapp" ng-controller="ExampleController">

<h2>AngularJS ng-class if example</h2>
<ul >
    <li ng-repeat="icolor in MyColors" >
        <p ng-class="[getClass(icolor), 'b']">{{icolor}}</p>
    </li>
</ul>
<hr/>
<p>Other way using : ng-class="{'class1' : expression1, 'class2' : expression2,'class3':expression2,...}"</p>
<ul>
    <li ng-repeat="icolor in MyColors">
        <p ng-class="{'Red':icolor=='It is Red','Yellow':icolor=='It is Yellow','Blue':icolor=='It is Blue','Green':icolor=='It is Green','Gray':icolor=='It is Gray'}" class="b">{{icolor}}</p>
    </li>
</ul>

Vous pouvez vous référer à la page de code complète à ng-class si exemple


9

Je suis nouveau sur Angular mais j'ai trouvé ceci pour résoudre mon problème:

<i class="icon-download" ng-click="showDetails = ! showDetails" ng-class="{'icon-upload': showDetails}"></i>

Cela appliquera conditionnellement une classe basée sur un var. Il commence par un téléchargement d'icône par défaut, en utilisant la classe ng, je vérifie le statut de showDetailssi true/falseet applique la classe téléchargement d'icône de . Cela fonctionne très bien.

J'espère que cela aide.


9

Ça fonctionne super bien ;)

<ul class="nav nav-pills" ng-init="selectedType = 'return'">
    <li role="presentation" ng-class="{'active':selectedType === 'return'}"
        ng-click="selectedType = 'return'"><a href="#return">return

    </a></li>
    <li role="presentation" ng-class="{'active':selectedType === 'oneway'}"
        ng-click="selectedType = 'oneway'"><a href="#oneway">oneway
    </a></li>
</ul>

5

Cela sera probablement revu à l'oubli, mais voici comment j'ai utilisé les opérateurs ternaires de 1.1.5 pour changer de classe selon que la ligne d'une table est la première, la moyenne ou la dernière - sauf s'il n'y a qu'une seule ligne dans la table:

<span class="attribute-row" ng-class="(restaurant.Attributes.length === 1) || ($first ? 'attribute-first-row': false || $middle ? 'attribute-middle-row': false || $last ? 'attribute-last-row': false)">
</span>

5

C'est dans mon travail plusieurs juges conditionnels:

<li ng-repeat='eOption in exam.examOptions' ng-class="exam.examTitle.ANSWER_COM==exam.examTitle.RIGHT_ANSWER?(eOption.eoSequence==exam.examTitle.ANSWER_COM?'right':''):eOption.eoSequence==exam.examTitle.ANSWER_COM?'wrong':eOption.eoSequence==exam.examTitle.RIGHT_ANSWER?'right':''">
  <strong>{{eOption.eoSequence}}</strong> &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;
  <span ng-bind-html="eOption.eoName | to_trusted">2020 元</span>
</li>

4

Voici une autre option qui fonctionne bien lorsque la classe ng ne peut pas être utilisée (par exemple lors du style SVG):

ng-attr-class="{{someBoolean && 'class-when-true' || 'class-when-false' }}"

(Je pense que vous devez être sur le dernier Angular instable pour utiliser ng-attr-, je suis actuellement sur 1.1.4)


4

eh bien je vous suggère de vérifier l'état de votre contrôleur avec une fonction retournant vrai ou faux .

<div class="week-wrap" ng-class="{today: getTodayForHighLight(todayDate, day.date)}">{{day.date}}</div>

et dans votre contrôleur vérifiez l'état

$scope.getTodayForHighLight = function(today, date){
return (today == date);
}

4

partiel

  <div class="col-md-4 text-right">
      <a ng-class="campaign_range === 'thismonth' ? 'btn btn-blue' :  'btn btn-link'" href="#" ng-click='change_range("thismonth")'>This Month</a>
      <a ng-class="campaign_range === 'all' ? 'btn btn-blue' :  'btn btn-link'" href="#" ng-click='change_range("all")'>All Time</a>
  </div>

manette

  $scope.campaign_range = "all";
  $scope.change_range = function(range) { 
        if (range === "all")
        {
            $scope.campaign_range = "all"
        }
        else
        {  
            $scope.campaign_range = "thismonth"
        }
  };

3

Si vous utilisez la version angulaire pré v1.1.5 (c'est-à-dire pas d'opérateur ternaire) et que vous souhaitez toujours une manière équivalente de définir une valeur dans les deux conditions, vous pouvez faire quelque chose comme ceci:

ng-class="{'class1':item.isReadOnly == false, 'class2':item.isReadOnly == true}"

3

Si vous avez une classe commune qui est appliquée à de nombreux éléments, vous pouvez créer une directive personnalisée qui ajoutera cette classe comme ng-show / ng-hide.

Cette directive ajoutera la classe 'active' au bouton si on clique dessus

module.directive('ngActive',  ['$animate', function($animate) {
  return function(scope, element, attr) {
    scope.$watch(attr.ngActive, function ngActiveWatchAction(value){
      $animate[value ? 'addClass' : 'removeClass'](element, 'active');
    });
  };
}]);

Plus d'informations



3

Vérifiez ça .

La tristement célèbre if|elsedéclaration AngularJS !!!
Quand j'ai commencé à utiliser Angularjs, j'ai été un peu surpris de ne pas trouver de déclaration if / else.

Je travaillais donc sur un projet et j'ai remarqué que lors de l'utilisation de l'instruction if / else, la condition s'affiche lors du chargement. Vous pouvez utiliser ng-cloak pour résoudre ce problème.

<div class="ng-cloak">
 <p ng-show="statement">Show this line</span>
 <p ng-hide="statement">Show this line instead</span>
</div>

.ng-cloak { display: none }

Merci amadou


0

Vous pouvez utiliser ce package npm. Il gère tout et a des options pour les classes statiques et conditionnelles basées sur une variable ou une fonction.

// Support for string arguments
getClassNames('class1', 'class2');

// support for Object
getClassNames({class1: true, class2 : false});

// support for all type of data
getClassNames('class1', 'class2', ['class3', 'class4'], { 
    class5 : function() { return false; },
    class6 : function() { return true; }
});

<div className={getClassNames({class1: true, class2 : false})} />
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.