Stel je hebt een array die wordt gerenderd in een ul
met een li
voor elk element en een property op de controller genaamd selectedIndex
. Wat zou de beste manier zijn om een class toe te voegen aan de li
met de index selectedIndex
in AngularJS?
Ik dupliceer momenteel (met de hand) de li
code en voeg de class toe aan een van de li
tags en gebruik ng-show
en ng-hide
om slechts een li
per index te tonen.
Als je geen CSS klasse-namen in Controller wilt zetten zoals ik doe, dan is hier een oude truc die ik gebruik sinds pre-v1 dagen. We kunnen een expressie schrijven die direct evalueert naar een klasse naam geselecteerd, geen aangepaste directieven zijn nodig:
ng:class="{true:'selected', false:''}[$index==selectedIndex]"
Let op de oude syntaxis met dubbele punt.
Er is ook een nieuwe betere manier om klassen conditioneel toe te passen, zoals:
ng-class="{selected: $index==selectedIndex}"
Angular ondersteunt nu expressies die een object teruggeven. Elke eigenschap (naam) van dit object wordt nu beschouwd als een klassenaam en wordt toegepast afhankelijk van de waarde ervan.
Deze manieren zijn echter niet functioneel gelijk. Hier is een voorbeeld:
ng-class="{admin:'enabled', moderator:'disabled', '':'hidden'}[user.role]"
We zouden dus bestaande CSS klassen kunnen hergebruiken door in principe een model eigenschap te mappen naar een klasse naam en tegelijkertijd CSS klassen uit Controller code te houden.
Hier is een veel eenvoudiger oplossing:
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>
Ik had onlangs een gelijkaardig probleem en besloot om gewoon een voorwaardelijk filter te maken:
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];
};
});
Het neemt één enkel argument, dat ofwel een array met 2 elementen is, ofwel een string, die wordt omgezet in een array waaraan als tweede element een lege string wordt toegevoegd:
<li ng-repeat="item in products | filter:search | orderBy:orderProp |
page:pageNum:pageLength" ng-class="'opened'|if:isOpen(item)">
...
</li>