¿Cuál es la mejor manera de aplicar una clase condicionalmente?

1183

Digamos que tiene una matriz que se representa en un ulcon un lipara cada elemento y una propiedad en el controlador llamado selectedIndex. ¿Cuál sería la mejor manera de agregar una clase al licon el índice selectedIndexen AngularJS?

Actualmente estoy duplicando (a mano) el licódigo y agregando la clase a una de las lietiquetas y usando ng-showy ng-hidepara mostrar solo una lipor índice.

respectTheCode
fuente
2
Las respuestas a esta pregunta muestran que hay más en la plantilla que {{varname}}. ¿Dónde puedo encontrar documentación de qué más hay para crear plantillas, como el operador ternario en un par de formas diferentes? docs.angularjs.org/guide/templates no parece explicar qué ofrecen las plantillas en términos de condicionales, etc. además de {{varname.fieldname}}.
Christos Hayward
esto es muy útil para mí, espero que funcione para usted tech-blog.maddyzone.com/javascript/…
Rituraj ratan

Respuestas:

1384

Si no desea poner nombres de clase CSS en el controlador como lo hago yo, aquí hay un viejo truco que uso desde los días anteriores a v1. Podemos escribir una expresión que evalúe directamente a un nombre de clase seleccionado , no se necesitan directivas personalizadas:

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

Tenga en cuenta la sintaxis anterior con dos puntos.

También hay una nueva forma mejor de aplicar clases condicionalmente, como:

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

Angular ahora admite expresiones que devuelven un objeto. Cada propiedad (nombre) de este objeto ahora se considera como un nombre de clase y se aplica según su valor.

Sin embargo, estas formas no son funcionalmente iguales. Aquí hay un ejemplo:

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

Por lo tanto, podríamos reutilizar las clases CSS existentes básicamente mapeando una propiedad de modelo a un nombre de clase y al mismo tiempo mantener las clases CSS fuera del código del controlador.

orcun
fuente
33
OP, esa puede ser la peor forma de expresar el operador ternario que he visto. ¿Lo has considerado ($index==selectedIndex) ? 'selected' : ''?
Malvolio
17
@Malvolio AFAIR, el operador ternario no funcionaba con expresiones angulares en v0.9.x. Esto es más o menos un cambio.
Orcun
36
ng-class (a partir del 19/01/2012) ahora admite una expresión que debe evaluar 1) una cadena de nombres de clase delimitados por espacios, o 2) y una matriz de nombres de clase, o 3) un mapa / objeto de clase nombres a valores booleanos. Entonces, usando 3): ng-class = "{selected: $ index == selectedIndex}"
Mark Rajcok
2
Gracias @ Mark, por cierto, ahora que lo he comprobado, puedo decir que este método funciona en v1. Sigue siendo útil en algunos casos. Tenga en cuenta que los nombres de propiedad de objeto (claves) no son necesariamente verdaderos o falsos, puede ser cualquier cosa que desee asignar a un nombre de clase.
orcun
66
Solo quiero agregar, estaba teniendo un problema porque estaba usando la sintaxis como {classname: '$index === selectedIndex'} y no funcionaba. Cuando puse todo junto y usé == en lugar de === funcionó. {classname: '$index==selectedIndex'}
Lucas
437

ng-class admite una expresión que debe evaluarse para

  1. Una cadena de nombres de clase delimitados por espacios, o
  2. Una matriz de nombres de clase, o
  3. Un mapa / objeto de nombres de clase a valores booleanos.

Entonces, usando el formulario 3) simplemente podemos escribir

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

Consulte también ¿Cómo aplico condicionalmente estilos CSS en AngularJS? para una respuesta más amplia


Actualización : Angular 1.1.5 ha agregado soporte para un operador ternario , por lo que si esa construcción te resulta más familiar:

ng-class="($index==selectedIndex) ? 'selected' : ''"
Mark Rajcok
fuente
2
+1 para operadores ternarios (y necesito uno ahora) pero 1.1. * Es una 'versión inestable' donde la API está sujeta a cambios sin previo aviso, al momento de escribir. 1.0. * Es estable, por lo que me sentiría más cómodo con eso para un proyecto que se implementará la próxima semana durante 6 meses.
Dave Everitt
1
ng-class="{'selected': $index==selectedIndex}"funciona para mí
knuhol
160

Mi método favorito es usar la expresión ternaria.

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

Nota: en caso de que estés usando una versión anterior de Angular, deberías usar esto en su lugar,

ng-class="condition && 'trueClass' || 'falseClass'"
skmvasu
fuente
2
Esto me ayudó a escribir esta expresión: ng-class="property.name=='timestamp' ? 'property-timestamp' : 'property-'+{{$index}}". No podría encontrar otra forma.
dduft
Realmente no encuentro por qué mi boolean modalFlag de ámbito no se está actualizando - ng-class = "{'closed': modalFlag, 'open':! ModalFlag}" Estoy tratando de agregar cerrado o abierto dependiendo de la variable de ámbito / boolean - Si alguien puede ayudar estaría muy agradecido -gracias.
aterrizó
Esto se introdujo como versión 1.5. github.com/angular/angular.js/commit/…
Mubashir Koul
55

Agregaré a esto, porque algunas de estas respuestas parecen desactualizadas. Así es como lo hago:

<class="ng-class:isSelected">

Donde 'isSelected' es una variable de JavaScript definida dentro del controlador angular con ámbito.


Para abordar más específicamente su pregunta, así es como puede generar una lista con eso:

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


Ver: http://jsfiddle.net/tTfWM/

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

stefano
fuente
¿Cuál es la diferencia entre class = "ng-class: item.isSelected" y ng-class = "item.isSelected"
Zloctb
¿Tienes curiosidad sobre el uso de ng-class:classNamevs solo el uso class="{{className}}"?
Roi
48

Aquí hay una solución mucho más 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>


fuente
74
Recomiendo encarecidamente mantener su controlador libre de CSS. Ese es un camino que no quieres seguir.
leviatán
1
Los nombres de clase pertenecen a la plantilla
Casey
55
En algún momento, jsfiddle puede fallar en pagar sus cuentas, o elegir mudarse a otro dominio, o las personas responsables son asesinadas por un autobús (ver también Factor de bus). Entonces, ¿puedo pedirle que explique qué hace ese violín en su respuesta? Esto también es canónico en el desbordamiento de pila.
Sebastian Mach
27

Recientemente me enfrenté a un problema similar y decidí crear un filtro condicional:

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

Se necesita un solo argumento, que es una matriz de 2 elementos o una cadena, que se convierte en una matriz que se agrega una cadena vacía como el segundo elemento:

<li ng-repeat="item in products | filter:search | orderBy:orderProp |
  page:pageNum:pageLength" ng-class="'opened'|if:isOpen(item)">
  ...
</li>
Lèse majesté
fuente
1
me acabo de crear por ejemplo un filtro yesNo () que devuelve las clases 'yes' o 'no' de acuerdo con un valor 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 puede manejar un mapa / objeto de nombres de clase a valores booleanos, por lo que simplemente podría escribir lo siguiente: ng-class = "{yes: some_boolean_expression, no: some_other_boolean_expression}" Por ejemplo, ng-class = "{yes: input , no
:!
21

Si desea ir más allá de la evaluación binaria y mantener su CSS fuera de su controlador, puede implementar un filtro simple que evalúe la entrada contra un objeto de mapa:

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

Esto le permite escribir su marcado de esta manera:

<div ng-class="muppets.star|switch:{'Kermit':'green', 'Miss Piggy': 'pink', 'Animal': 'loud'}">
    ...
</div>
Joe Steele
fuente
Hola @ Joe, ¿alguna idea de cómo manejar valores nulos? Si paso nulo en la entrada, no
asignará
1
@ user1191559: podría incluir un elemento 'predeterminado' en el mapa y luego devolver ese valor si 'input' es nulo.
Joe Steele
17

Lo que hice recientemente fue hacer esto:

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

El isShowingvalor es un valor que se encuentra en mi controlador que se alterna con el clic de un botón y las partes entre paréntesis individuales son clases que creé en mi archivo css.

EDITAR: También me gustaría agregar que codeschool.com tiene un curso gratuito patrocinado por google en AngularJS que repasa todo esto y algo más. No hay necesidad de pagar por nada, ¡simplemente regístrese para obtener una cuenta y comience! ¡La mejor de las suertes para todos ustedes!

Pytth
fuente
¿Podría proporcionar un violín o más código aquí? ¿ isShowingEntonces hay una matriz en el controlador?
Kyle Pennell
Supongo que es un booleano
Mirko
15

El operador ternario se acaba de agregar al analizador angular en 1.1.5 .

Entonces, la forma más sencilla de hacer esto es ahora:

ng:class="($index==selectedIndex)? 'selected' : ''"
Lionroots
fuente
También: class="otherClass ng-class:($index==selectedIndex)? 'selected' : '';".
Peter
11

Podemos hacer una función para gestionar la clase de retorno con condición

ingrese la descripción de la imagen aquí

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

Y entonces

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

Puede consultar la página de códigos completa en ng-class si es un ejemplo

Lewis Hai
fuente
9

Soy nuevo en Angular pero he encontrado esto para resolver mi problema:

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

Esto aplicará condicionalmente una clase basada en una var. Comienza con una descarga de iconos por defecto, usando ng-class, verifico el estado de showDetailsif true/falsey aplico la carga de iconos de clase . Funciona muy bien.

Espero eso ayude.

Ravi Ram
fuente
9

Esto funciona como un encanto;)

<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>
Aliti
fuente
5

Probablemente, esto se reducirá al olvido, pero así es como utilicé los operadores ternarios de 1.1.5 para cambiar de clase dependiendo de si una fila en una tabla es la primera, la media o la última, excepto si solo hay una fila en la tabla:

<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>
Sundar
fuente
5

Esto está en mi trabajo juzgar condicionalmente múltiples:

<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>
H.jame
fuente
4

Aquí hay otra opción que funciona bien cuando no se puede usar ng-class (por ejemplo, al diseñar SVG):

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

(Creo que necesitas estar en el último Angular inestable para usar ng-attr-, actualmente estoy en 1.1.4)

Ashley Davis
fuente
4

bueno, le sugiero que verifique la condición en su controlador con una función que devuelva verdadero o falso .

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

y en su controlador verifique la condición

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

parcial

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

controlador

  $scope.campaign_range = "all";
  $scope.change_range = function(range) { 
        if (range === "all")
        {
            $scope.campaign_range = "all"
        }
        else
        {  
            $scope.campaign_range = "thismonth"
        }
  };
Caner Çakmak
fuente
3

Si está utilizando angular pre v1.1.5 (es decir, sin operador ternario) y aún desea una forma equivalente de establecer un valor en ambas condiciones, puede hacer algo como esto:

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

Si tiene una clase común que se aplica a muchos elementos, puede crear una directiva personalizada que agregará esa clase como ng-show / ng-hide.

Esta directiva agregará la clase 'activa' al botón si se hace clic en ella

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

Más información

lars1595
fuente
3

Solo agregué algo que funcionó para mí hoy, después de mucho buscar ...

<div class="form-group" ng-class="{true: 'has-error'}[ctrl.submitted && myForm.myField.$error.required]">

Espero que esto ayude en su desarrollo exitoso.

=)

Sintaxis de Expresión Indocumentada: Gran Enlace al Sitio Web ... =)

Robert Green MBA
fuente
Mira la respuesta aceptada. Está haciendo lo mismo y da más ejemplos.
respectTheCode
3

Mira esto .

¡La infame if|elsedeclaración de AngularJS !
Cuando comencé a usar Angularjs, me sorprendió un poco que no pudiera encontrar una declaración if / else.

Así que estaba trabajando en un proyecto y noté que al usar la instrucción if / else, la condición se muestra mientras se carga. Puedes usar ng-cloak para arreglar esto.

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

Gracias amadou

Victor cruz
fuente
0

Puedes usar este paquete npm. Maneja todo y tiene opciones para clases estáticas y condicionales basadas en una variable o una función.

// 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})} />
Tushar Sharma
fuente