Qual é a melhor maneira de aplicar condicionalmente uma classe?

1183

Digamos que você tenha uma matriz que é renderizada em um ulcom um lipara cada elemento e uma propriedade no controlador chamada selectedIndex. Qual seria a melhor maneira de adicionar uma classe ao liíndice selectedIndexno AngularJS?

No momento, estou duplicando (manualmente) o licódigo e adicionando a classe a uma das litags, usando ng-showe ng-hidepara mostrar apenas uma lipor índice.

respectTheCode
fonte
2
As respostas a esta pergunta mostram que há mais na modelagem do que {{varname}}. Onde posso encontrar documentação do que mais há para modelar, como o operador ternário de duas formas diferentes? docs.angularjs.org/guide/templates parece não explicar o que o modelo oferece em termos de condicionais etc. além de {{varname.fieldname}}.
Christos Hayward
isso é muito útil para mim, espero que funcione para você tech-blog.maddyzone.com/javascript/…
#

Respostas:

1384

Se você não deseja colocar nomes de classes CSS no Controller, como eu, aqui está um truque antigo que eu uso desde os dias anteriores à v1. Podemos escrever uma expressão que seja avaliada diretamente em um nome de classe selecionado , nenhuma diretiva personalizada é necessária:

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

Observe a sintaxe antiga com dois pontos.

Há também uma nova maneira melhor de aplicar classes condicionalmente, como:

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

Angular agora suporta expressões que retornam um objeto. Cada propriedade (nome) deste objeto agora é considerada como um nome de classe e é aplicada dependendo do seu valor.

No entanto, essas maneiras não são funcionalmente iguais. Aqui está um exemplo:

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

Portanto, poderíamos reutilizar as classes CSS existentes, mapeando basicamente uma propriedade de modelo para um nome de classe e, ao mesmo tempo, mantendo as classes CSS fora do código do Controller.

orcun
fonte
33
OP, essa pode ser a pior maneira de expressar o operador ternário que eu já vi. Você já considerou ($index==selectedIndex) ? 'selected' : ''?
Malvolio
17
@ Malvolio AFAIR, operador ternário não estava trabalhando com expressões angulares na v0.9.x. Isso é mais ou menos um interruptor.
orcun
36
ng-class (em 19/01/2012) agora suporta uma expressão que deve ser avaliada como 1) uma sequência de nomes de classe delimitados por espaço, ou 2) e uma matriz de nomes de classes, ou 3) um mapa / objeto de classe nomes para valores booleanos. Portanto, usando 3): ng-class = "{selected: $ index == selectedIndex}"
Mark Rajcok 28/08/2012
2
Obrigado @Mark, agora que verifiquei, posso dizer que esse método está funcionando na v1. Ainda é útil em alguns casos. Observe que os nomes de propriedades do objeto (chaves) não são necessariamente verdadeiros ou falsos; pode ser qualquer coisa que você queira mapear para um nome de classe.
orcun 29/08/12
6
Eu só quero adicionar, eu estava tendo um problema porque estava usando uma sintaxe do tipo {classname: '$index === selectedIndex'} e não estava funcionando. Quando juntei tudo e usei == em vez de ===, funcionou. {classname: '$index==selectedIndex'}
Lucas
437

A classe ng suporta uma expressão que deve ser avaliada para

  1. Uma sequência de nomes de classe delimitados por espaço ou
  2. Uma matriz de nomes de classe ou
  3. Um mapa / objeto de nomes de classe para valores booleanos.

Então, usando o formulário 3) podemos simplesmente escrever

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

Consulte também Como aplico condicionalmente estilos CSS no AngularJS? para uma resposta mais ampla.


Atualização : O Angular 1.1.5 adicionou suporte para um operador ternário , portanto, se essa construção é mais familiar para você:

ng-class="($index==selectedIndex) ? 'selected' : ''"
Mark Rajcok
fonte
2
+1 para operadores ternários (e eu preciso de um agora), mas 1.1. * É uma 'versão instável' em que a API está sujeita a alterações sem aviso prévio - no momento da digitação. 1.0. * É estável, então eu ficaria mais à vontade com isso para que um projeto seja lançado na próxima semana por 6 meses.
26813 Dave Everitt
1
ng-class="{'selected': $index==selectedIndex}"trabalha para mim
knuhol 6/02/15
160

Meu método favorito é usar a expressão ternária.

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

Nota: Caso esteja usando uma versão mais antiga do Angular, você deve usá-lo,

ng-class="condition && 'trueClass' || 'falseClass'"
skmvasu
fonte
2
Isso me ajudou a escrever esta expressão: ng-class="property.name=='timestamp' ? 'property-timestamp' : 'property-'+{{$index}}". Não foi possível descobrir de outra maneira.
dduft
Realmente não estou descobrindo por que meu modalFlag booleano com escopo não está atualizando - ng-class = "{'closed': modalFlag, 'open':! ModalFlag}" Estou tentando adicionar fechado ou aberto, dependendo da variável com escopo / booleano - se alguém puder ajudar eu ficaria muito grato - obrigado.
desembarcou
Isso foi introduzido na versão 1.5. github.com/angular/angular.js/commit/…
Mubashir Koul 15/02
55

Vou acrescentar a isso, porque algumas dessas respostas parecem desatualizadas. Aqui está como eu faço:

<class="ng-class:isSelected">

Onde 'isSelected' é uma variável javascript definida no controlador angular com escopo definido.


Para abordar mais especificamente sua pergunta, veja como você pode gerar uma lista com isso:

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


Veja: http://jsfiddle.net/tTfWM/

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

Stefano
fonte
O que é diferente entre class = "ng-class: item.isSelected" e ng-class = "item.isSelected"
zloctb
Curioso sobre o uso de ng-class:classNamevs apenas usando class="{{className}}"?
Roi
48

Aqui está uma solução muito mais simples:

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>


fonte
74
Eu recomendo manter o seu controlador livre de coisas CSS. Esse é um caminho que você não deseja seguir.
leviathan
1
Os nomes das classes pertencem ao modelo
Casey
5
Em algum momento, o jsfiddle pode deixar de pagar suas contas, ou optar por mudar para outro domínio, ou as pessoas responsáveis ​​são mortas por um ônibus (veja também Bus Factor). Então, posso pedir que você explique o que esse violino faz, dentro da sua resposta? Isso também é canônico no estouro de pilha.
Sebastian Mach
27

Enfrentei um problema semelhante recentemente e decidi criar apenas um 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];
      };
    });

É necessário um único argumento, que é uma matriz de 2 elementos ou uma sequência, que é transformada em uma matriz que é anexada a uma sequência vazia como o 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é
fonte
1
eu acabei de criar por exemplo um filtro yesNo () retornando classes 'yes' ou 'no' de acordo com um 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
A ng-class pode manipular um mapa / objeto de nomes de classe com valores booleanos, então você pode simplesmente escrever o seguinte: ng-class = "{yes: some_boolean_expression, no: some_other_boolean_expression}" Por exemplo, ng-class = "{yes: input , no
:!
21

Se você deseja ir além da avaliação binária e manter seu CSS fora do seu controlador, pode implementar um filtro simples que avalia a entrada em relação a um objeto de mapa:

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

Isso permite que você escreva sua marcação assim:

<div ng-class="muppets.star|switch:{'Kermit':'green', 'Miss Piggy': 'pink', 'Animal': 'loud'}">
    ...
</div>
Joe Steele
fonte
Oi @ Joe, alguma idéia de como lidar com valores nulos? Se eu passar em nulo na entrada, ele não vai mapear sua classe ...
dalcam
1
@ user1191559 - você pode colocar um item 'padrão' no mapa e retornar esse valor se 'input' for nulo.
Joe Steele
17

O que eu fiz recentemente foi o que estava fazendo isso:

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

O isShowingvalor é um valor localizado no meu controlador que é alternado com o clique de um botão e as partes entre parênteses únicos são classes que eu criei no meu arquivo css.

EDIT: Gostaria também de acrescentar que o codeschool.com tem um curso gratuito patrocinado pelo google no AngularJS que aborda todas essas coisas e mais algumas. Não há necessidade de pagar por nada, basta se inscrever em uma conta e seguir em frente! Boa sorte a todos!

Pytth
fonte
Você poderia fornecer um violino ou mais código aqui? Existe isShowinguma matriz no controlador?
precisa
Eu acho que é um boolean
Mirko
15

O operador ternário acabou de ser adicionado ao analisador angular no 1.1.5 .

Portanto, a maneira mais simples de fazer isso é agora:

ng:class="($index==selectedIndex)? 'selected' : ''"
raízes de leão
fonte
Também: class="otherClass ng-class:($index==selectedIndex)? 'selected' : '';".
peter
11

Podemos criar uma função para gerenciar a classe de retorno com a condição

insira a descrição da imagem aqui

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

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

Você pode consultar a página de código completa na classe ng, por exemplo

Lewis Hai
fonte
9

Eu sou novo no Angular, mas achei isso para resolver meu problema:

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

Isso aplicará condicionalmente uma classe com base em uma var. Começa com um download de ícone como padrão, a classe ng usando, verifico o status de showDetailsse true/falsee aplico o upload de ícones da classe . Está funcionando muito bem.

Espero que ajude.

Ravi Ram
fonte
9

Isso funciona como um 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
fonte
5

Isso provavelmente será reduzido para o esquecimento, mas aqui está como eu usei os operadores ternários do 1.1.5 para alternar classes, dependendo de uma linha em uma tabela ser a primeira, a média ou a última - exceto se houver apenas uma linha na tabela:

<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>
pôr do sol
fonte
5

Este é no meu trabalho vários juízes condicionais:

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

Aqui está outra opção que funciona bem quando a classe ng não pode ser usada (por exemplo, ao estilizar SVG):

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

(Eu acho que você precisa estar no mais recente angular instável para usar ng-attr-, atualmente estou no 1.1.4)

Ashley Davis
fonte
4

Bem, eu sugiro que você verifique a condição no seu controlador com uma função retornando true ou false .

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

e no seu controlador verifique a condição

$scope.getTodayForHighLight = function(today, date){
return (today == date);
}
sheelpriy
fonte
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
fonte
3

Se você estiver usando o angular pré v1.1.5 (ou seja, nenhum operador ternário) e ainda desejar uma maneira equivalente de definir um valor nas duas condições, poderá fazer algo assim:

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

Se você tiver uma classe comum aplicada a muitos elementos, poderá criar uma diretiva personalizada que irá adicionar essa classe como ng-show / ng-hide.

Esta diretiva adicionará a classe 'ativa' ao botão se for clicada

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

Mais informações

lars1595
fonte
3

Apenas adicionando algo que funcionou para mim hoje, depois de muita pesquisa ...

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

Espero que isso ajude no seu desenvolvimento bem-sucedido.

=)

Sintaxe de expressão não documentada: ótimo link para o site ... =)

Robert Green MBA
fonte
Confira a resposta aceita. Está fazendo a mesma coisa e dá mais exemplos.
respectTheCode
3

Verifique isso .

A infame if|elsedeclaração AngularJS !!!
Quando comecei a usar o Angularjs, fiquei um pouco surpreso por não encontrar uma instrução if / else.

Então, eu estava trabalhando em um projeto e notei que, ao usar a instrução if / else, a condição é exibida durante o carregamento. Você pode usar o ng-cloak para corrigir isso.

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

Obrigado amadou

Victor Cruz
fonte
0

Você pode usar este pacote npm. Ele lida com tudo e tem opções para classes estáticas e condicionais com base em uma variável ou uma função.

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