Vamos dizer que você tem um array que é renderizado em um "ul" com um "li" para cada elemento e uma propriedade no controlador chamada "setlectedIndex". Qual seria a melhor maneira de adicionar uma classe ao li
com o índice selectedIndex
em AngularJS?
Atualmente estou duplicando (à mão) o código li
e adicionando a classe a uma das tags li
e utilizando ng-show
e ng-hide
para mostrar apenas um li
por índice.
Se você não quer colocar nomes de classe CSS no Controller como eu faço, aqui está um velho truque que eu uso desde os dias pré-v1. Podemos escrever uma expressão que avalia diretamente para um nome de classe selecionado, nenhuma diretriz personalizada é necessária:
ng:class="{true:'selected', false:''}[$index==selectedIndex]"
Por favor note a velha sintaxe com cólon.
Há também uma nova maneira melhor de aplicar as aulas condicionalmente, como por exemplo:
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, estas formas não são funcionalmente iguais. Aqui está um exemplo:
ng-class="{admin:'enabled', moderator:'disabled', '':'hidden'}[user.role]"
Assim, poderíamos reutilizar classes CSS existentes mapeando basicamente uma propriedade modelo para um nome de classe e ao mesmo tempo manter as classes CSS fora do código Controller.
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>
Eu enfrentei um problema semelhante recentemente e decidi apenas criar 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 é ou um array de 2 elementos ou uma string, que é transformado em um array que é anexado uma string 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>