angularjs - example - Función de clasificación personalizada en ng-repeat
ng-repeat order by (3)
El siguiente enlace explica los filtros en Angular extremadamente bien. Muestra cómo es posible definir una lógica de ordenación personalizada dentro de una repetición ng. http://toddmotto.com/everything-about-custom-filters-in-angular-js
Para clasificar objeto con propiedades, este es el código que he usado: (Tenga en cuenta que este tipo es el método de ordenación estándar de JavaScript y no específico de angular) Nombre de columna es el nombre de la propiedad en la que se va a realizar la clasificación.
self.myArray.sort(function(itemA, itemB) {
if (self.sortOrder === "ASC") {
return itemA[columnName] > itemB[columnName];
} else {
return itemA[columnName] < itemB[columnName];
}
});
Tengo un conjunto de fichas que muestran un cierto número según la opción seleccionada por el usuario. Ahora quisiera implementar un orden por cualquier número que se muestre.
El siguiente código muestra cómo lo he implementado (al obtener / establecer un valor en el alcance de las tarjetas principales). Ahora, debido a que la función orderBy toma una cadena, traté de establecer una variable en el alcance de la tarjeta llamada curOptionValue y ordenar por eso, pero parece que no funciona.
Entonces, la pregunta es: ¿cómo puedo crear una función de clasificación personalizada?
<div ng-controller="aggViewport" >
<div class="btn-group" >
<button ng-click="setOption(opt.name)" ng-repeat="opt in optList" class="btn active">{{opt.name}}</button>
</div>
<div id="container" iso-grid width="500px" height="500px">
<div ng-repeat="card in cards" class="item {{card.class}}" ng-controller="aggCardController">
<table width="100%">
<tr>
<td align="center">
<h4>{{card.name}}</h4>
</td>
</tr>
<tr>
<td align="center"><h2>{{getOption()}}</h2></td>
</tr>
</table>
</div>
</div>
y controlador:
module.controller(''aggViewport'',[''$scope'',''$location'',function($scope,$location) {
$scope.cards = [
{name: card1, values: {opt1: 9, opt2: 10}},
{name: card1, values: {opt1: 9, opt2: 10}}
];
$scope.option = "opt1";
$scope.setOption = function(val){
$scope.option = val;
}
}]);
module.controller(''aggCardController'',[''$scope'',function($scope){
$scope.getOption = function(){
return $scope.card.values[$scope.option];
}
}]);
En realidad, el filtro orderBy
puede tomar como parámetro no solo una cadena sino también una función. De la documentación de orderBy
: http://docs.angularjs.org/api/ng.filter:orderBy ):
función: función Getter. El resultado de esta función se ordenará usando el operador <, =,>.
Entonces, podrías escribir tu propia función. Por ejemplo, si desea comparar tarjetas basadas en una suma de opt1 y opt2 (lo estoy inventando, el punto es que puede tener cualquier función arbitraria) que escribiría en su controlador:
$scope.myValueFunction = function(card) {
return card.values.opt1 + card.values.opt2;
};
y luego, en tu plantilla:
ng-repeat="card in cards | orderBy:myValueFunction"
Aquí está el jsFiddle de trabajo
Otra cosa digna de mención es que orderBy
es solo un ejemplo de filtros AngularJS, por lo que si necesita un comportamiento de pedido muy específico, puede escribir su propio filtro (aunque orderBy
debería ser suficiente para la mayoría de los casos de uso).
La solución aceptada solo funciona en arreglos, pero no en objetos o matrices asociativas. Desafortunadamente, dado que Angular depende de la implementación de JavaScript de la enumeración de matrices, el orden de las propiedades del objeto no se puede controlar de manera uniforme. Algunos navegadores pueden iterar lexicográficamente a través de las propiedades de los objetos, pero esto no se puede garantizar.
Por ejemplo, dada la siguiente asignación:
$scope.cards = {
"card2": {
values: {
opt1: 9,
opt2: 12
}
},
"card1": {
values: {
opt1: 9,
opt2: 11
}
}
};
y la directiva <ul ng-repeat="(key, card) in cards | orderBy:myValueFunction">
, ng-repeat puede iterar sobre "card1" antes de "card2", independientemente del orden de clasificación.
Para solucionar esto, podemos crear un filtro personalizado para convertir el objeto a una matriz, y luego aplicar una función de clasificación personalizada antes de devolver la colección.
myApp.filter(''orderByValue'', function () {
// custom value function for sorting
function myValueFunction(card) {
return card.values.opt1 + card.values.opt2;
}
return function (obj) {
var array = [];
Object.keys(obj).forEach(function (key) {
// inject key into each object so we can refer to it from the template
obj[key].name = key;
array.push(obj[key]);
});
// apply a custom sorting function
array.sort(function (a, b) {
return myValueFunction(b) - myValueFunction(a);
});
return array;
};
});
No podemos iterar sobre emparejamientos (clave, valor) junto con filtros personalizados (dado que las claves para las matrices son índices numéricos), por lo que la plantilla debe actualizarse para hacer referencia a los nombres de clave inyectados.
<ul ng-repeat="card in cards | orderByValue">
<li>{{card.name}} {{value(card)}}</li>
</ul>
Aquí hay un violín que funciona utilizando un filtro personalizado en una matriz asociativa: http://jsfiddle.net/av1mLpqx/1/
Referencia: https://github.com/angular/angular.js/issues/1286#issuecomment-22193332