Qual è il modo migliore per applicare una classe in modo condizionale?


1183

Diciamo che hai un array che viene reso in un ulcon un liper ogni elemento e una proprietà sul controller chiamata selectedIndex. Quale sarebbe il modo migliore per aggiungere una classe liall'indice selectedIndexin AngularJS?

Attualmente sto duplicando (a mano) il licodice e aggiungendo la classe a uno dei litag e usando ng-showe ng-hideper mostrarne solo uno liper indice.


2
Le risposte a questa domanda mostrano che ci sono altre cose nel template rispetto a {{varname}}. Dove posso trovare la documentazione di cosa c'è di più nel modello, come l'operatore ternario in un paio di forme diverse? docs.angularjs.org/guide/templates non sembra spiegare cosa offre il modello in termini di condizioni, ecc. oltre a {{varname.fieldname}}.
Christos Hayward,

questo è così utile per me spero che funzionerà per te tech-blog.maddyzone.com/javascript/…
Rituraj ratan,

Risposte:


1384

Se non vuoi inserire i nomi delle classi CSS in Controller come faccio io, ecco un vecchio trucco che uso dai giorni precedenti alla prima. Possiamo scrivere un'espressione che valuta direttamente il nome di una classe selezionata , non sono necessarie direttive personalizzate:

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

Nota la vecchia sintassi con i due punti.

Esiste anche un nuovo modo migliore di applicare le classi in modo condizionale, come:

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

Angular ora supporta espressioni che restituiscono un oggetto. Ogni proprietà (nome) di questo oggetto è ora considerata come un nome di classe e viene applicata in base al suo valore.

Tuttavia questi modi non sono funzionalmente uguali. Ecco un esempio:

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

Potremmo quindi riutilizzare le classi CSS esistenti fondamentalmente mappando una proprietà del modello su un nome di classe e allo stesso tempo mantenere le classi CSS fuori dal codice del controller.


33
OP, potrebbe essere il modo peggiore di esprimere l'operatore ternario che abbia mai visto. Hai preso in considerazione ($index==selectedIndex) ? 'selected' : ''?
Malvolio,

17
@Malvolio AFAIR, operatore ternario non funzionava con espressioni angolari in v0.9.x. Questo è più o meno un interruttore.
orcun '

36
ng-class (dal 1/19/2012) ora supporta un'espressione che deve valutare 1) una stringa di nomi di classe delimitati da spazi, oppure 2) e array di nomi di classi, oppure 3) una mappa / oggetto di classe nomi a valori booleani. Quindi, usando 3): ng-class = "{selected: $ index == selectedIndex}"
Mark Rajcok,

2
Grazie @Mark, BTW ora che ho controllato posso dire che questo metodo funziona in v1. È ancora utile in alcuni casi. Nota che i nomi delle proprietà degli oggetti (chiavi) non sono necessariamente veri o falsi, può essere qualsiasi cosa tu voglia associare a un nome di classe.
orcun

6
Voglio solo aggiungere, ho avuto un problema perché stavo usando la sintassi come {classname: '$index === selectedIndex'} e non funzionava. Quando ho messo tutto insieme e usato == invece di === ha funzionato. {classname: '$index==selectedIndex'}
Lucas,

437

ng-class supporta un'espressione che deve valutare in entrambi

  1. Una stringa di nomi di classe delimitati da spazi o
  2. Una matrice di nomi di classe o
  3. Una mappa / oggetto di nomi di classe per valori booleani.

Quindi, usando il modulo 3) possiamo semplicemente scrivere

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

Vedi anche Come posso applicare in modo condizionale gli stili CSS in AngularJS? per una risposta più ampia.


Aggiornamento : Angular 1.1.5 ha aggiunto il supporto per un operatore ternario , quindi se quel costrutto ti è più familiare:

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

2
+1 per gli operatori ternari (e ne ho bisogno uno in questo momento) ma 1.1. * È una "versione instabile" in cui l'API è soggetta a modifiche senza preavviso - al momento della digitazione. 1.0. * È stabile, quindi sarei più a mio agio nel farlo per un progetto che verrà lanciato la prossima settimana per 6 mesi.
Dave Everitt,

1
ng-class="{'selected': $index==selectedIndex}"funziona per me
knuhol

160

Il mio metodo preferito sta usando l'espressione ternaria.

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

Nota: nel caso in cui tu stia utilizzando una versione precedente di Angular, dovresti invece utilizzarla,

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

2
Questo mi ha aiutato a scrivere questa espressione: ng-class="property.name=='timestamp' ? 'property-timestamp' : 'property-'+{{$index}}". Impossibile capire in altro modo.
Dduft

Non sto davvero scoprendo perché il mio modalFlag booleano con ambito non si aggiorni - ng-class = "{'closed': modalFlag, 'open':! ModalFlag}" Sto provando ad aggiungere sia chiuso che aperto a seconda della variabile / booleano con ambito - se qualcuno può aiutarti, ti sarei molto grato - grazie.
sbarcò

Questo è stato introdotto come versione 1.5. github.com/angular/angular.js/commit/…
Mubashir Koul

55

Aggiungerò a questo, perché alcune di queste risposte sembrano obsolete. Ecco come lo faccio:

<class="ng-class:isSelected">

Dove 'isSelected' è una variabile javascript definita all'interno del controller angolare con ambito.


Per rispondere in modo più specifico alla tua domanda, ecco come potresti generare un elenco con quello:

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": ""}
    ]
}


Vedere: http://jsfiddle.net/tTfWM/

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


Qual è la differenza tra class = "ng-class: item.isSelected" e ng-class = "item.isSelected"
zloctb

Sei curioso di usare il ng-class:classNamevs solo usando class="{{className}}"?
Roi,

48

Ecco una soluzione molto più semplice:

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
Consiglio vivamente di tenere il controller libero dalle cose CSS. Questo è un percorso che non vuoi seguire.
leviatano,

1
I nomi delle classi appartengono al modello
Casey,

5
Ad un certo punto, jsfiddle potrebbe non riuscire a pagare le bollette o scegliere di spostarsi in un altro dominio, oppure le persone responsabili vengono uccise da un autobus (vedi anche Fattore di bus). Quindi posso chiederti di spiegare cosa fa quel violino, nella tua risposta? Questo è anche canonico su overflow dello stack.
Sebastian Mach,

27

Di recente ho riscontrato un problema simile e ho deciso di creare un filtro condizionale:

  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];
      };
    });

Prende un singolo argomento, che è una matrice a 2 elementi o una stringa, che viene trasformata in una matrice a cui viene aggiunta una stringa vuota come secondo elemento:

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

1
me to I appena creato per esempio un filtro yesNo () che restituisce le classi 'yes' o 'no' in base a un valore booleano 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 può gestire una mappa / oggetto di nomi di classe su valori booleani, quindi puoi semplicemente scrivere quanto segue: ng-class = "{yes: some_boolean_expression, no: some_other_boolean_expression}" Ad esempio, ng-class = "{yes: input , no
:!

21

Se vuoi andare oltre la valutazione binaria e tenere il CSS fuori dal controller, puoi implementare un semplice filtro che valuta l'input rispetto a un oggetto mappa:

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

Ciò ti consente di scrivere il tuo markup in questo modo:

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

Ciao @Joe, qualche idea su come gestire i valori null? Se inserisco null nell'input, non
mapperà la

1
@utente1191559 - è possibile un elemento "predefinito" sulla mappa, quindi restituire quel valore se "input" è nullo.
Joe Steele,

17

Quello che ho fatto di recente è stato questo:

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

Il isShowing valore è un valore che si trova sul mio controller che viene attivato con il clic di un pulsante e le parti tra parentesi singole sono le classi che ho creato nel mio file CSS.

EDIT: Vorrei anche aggiungere che codeschool.com ha un corso gratuito che è sponsorizzato da Google su AngularJS che copre tutte queste cose e poi alcune. Non è necessario pagare nulla, basta registrarsi per un account e iniziare! Buona fortuna a tutti voi!


Potresti fornire un violino o più codice qui? È isShowingun array in controllore, allora?
Kyle Pennell,

Immagino sia un booleano
Mirko l'

15

L'operatore ternario è stato appena aggiunto al parser angolare in 1.1.5 .

Quindi il modo più semplice per farlo è ora:

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

Inoltre: class="otherClass ng-class:($index==selectedIndex)? 'selected' : '';".
Pietro,

11

Possiamo fare una funzione per gestire la classe di ritorno con condizione

inserisci qui la descrizione dell'immagine

<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>

E poi

<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>

Puoi fare riferimento alla pagina di codice completa in ng-class, se esempio


9

Sono nuovo di Angular ma ho trovato questo per risolvere il mio problema:

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

Ciò applicherà in modo condizionale una classe basata su una var. Si inizia con il download di un'icona come impostazione predefinita, utilizzando ng-class, controllo lo stato di showDetailsif true/falsee applico il caricamento dell'icona di classe . Funziona benissimo.

Spero che sia d'aiuto.


9

Funziona come un fascino;)

<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

Questo probabilmente verrà ridimensionato all'oblio, ma ecco come ho usato gli operatori ternari di 1.1.5 per cambiare classe a seconda che una riga in una tabella sia la prima, la metà o l'ultima - tranne se c'è solo una riga nella tabella:

<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

Questo è nel mio lavoro più condizionale giudicare:

<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

Ecco un'altra opzione che funziona bene quando non è possibile utilizzare ng-class (ad esempio quando si disegna lo SVG):

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

(Penso che devi essere sull'ultimo Angolare instabile per usare ng-attr-, al momento sono su 1.1.4)


4

bene ti suggerirei di controllare le condizioni nel tuo controller con una funzione che ritorna vera o falsa .

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

e nel controller controlla le condizioni

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

4

parziale

  <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>

controllore

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

3

Se si utilizza angular pre v1.1.5 (ovvero nessun operatore ternario) e si desidera comunque un modo equivalente di impostare un valore in entrambe le condizioni, è possibile eseguire una operazione del genere:

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

3

Se hai una classe comune che viene applicata a molti elementi, puoi creare una direttiva personalizzata che aggiungerà quella classe come ng-show / ng-hide.

Questa direttiva aggiungerà la classe "attivo" al pulsante se viene cliccato

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

Ulteriori informazioni



3

Controlla questo .

La famigerata if|elsedichiarazione di AngularJS !!!
Quando ho iniziato a usare Angularjs, sono rimasto un po 'sorpreso di non riuscire a trovare un'istruzione if / else.

Quindi stavo lavorando a un progetto e ho notato che quando si utilizza l'istruzione if / else, la condizione viene visualizzata durante il caricamento. Puoi usare ng-cloak per risolvere questo problema.

<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 }

Grazie amadou


0

Puoi usare questo pacchetto npm. Gestisce tutto e ha opzioni per classi statiche e condizionali basate su una variabile o una funzione.

// 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})} />
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.