AngularJS triagem por propriedade

O que estou tentando fazer é classificar alguns dados por propriedade. Aqui está o exemplo que eu pensei que deveria funcionar, mas isso não acontece.

Parte HTML:

  • {{value.order}}. {{key}} -> {{value.name}}

Parte JS:

 var myApp = angular.module('myApp', []); myApp.controller('controller', ['$scope', function ($scope) { $scope.testData = { C: {name:"CData", order: 1}, B: {name:"BData", order: 2}, A: {name:"AData", order: 3}, } }]); 

E o resultado:

  1. A -> AData
  2. B -> BData
  3. C -> CData

… que IMHO deve ficar assim:

  1. C -> CData
  2. B -> BData
  3. A -> AData

Eu perdi alguma coisa (aqui está pronto JSFiddle para experimentar)?

O filtro orderBy do AngularJS apenas suporta matrizes – sem objects. Então você tem que escrever um filtro pequeno, que faz a sorting para você.

Ou altere o formato dos dados com os quais você lida (se tiver influência sobre isso). Uma matriz contendo objects é classificável pelo filtro orderBy nativo.

Aqui está o meu filtro orderObjectBy para AngularJS:

 app.filter('orderObjectBy', function(){ return function(input, attribute) { if (!angular.isObject(input)) return input; var array = []; for(var objectKey in input) { array.push(input[objectKey]); } array.sort(function(a, b){ a = parseInt(a[attribute]); b = parseInt(b[attribute]); return a - b; }); return array; } }); 

Uso em sua opinião:

 
//...

O object precisa, neste exemplo, de um atributo position, mas você tem a flexibilidade de usar qualquer atributo em objects (contendo um inteiro), apenas por definição.

Exemplo de JSON:

 { "123": {"name": "Test B", "position": "2"}, "456": {"name": "Test A", "position": "1"} } 

Aqui está um violino que mostra o uso: http://jsfiddle.net/4tkj8/1/

É bem fácil, apenas faça assim

 $scope.props = [{order:"1"},{order:"5"},{order:"2"}] ng-repeat="prop in props | orderBy:'order'" 

Não se esqueça de que parseInt () só funciona para valores inteiros. Para classificar valores de string, você precisa trocar isso:

 array.sort(function(a, b){ a = parseInt(a[attribute]); b = parseInt(b[attribute]); return a - b; }); 

com isso:

 array.sort(function(a, b){ var alc = a[attribute].toLowerCase(), blc = b[attribute].toLowerCase(); return alc > blc ? 1 : alc < blc ? -1 : 0; }); 

Como você pode ver no código de JS angular ( https://github.com/angular/angular.js/blob/master/src/ng/filter/orderBy.js ) ng-repeat não funciona com objects. Aqui está um hack com sortFunction.

http://jsfiddle.net/sunnycpp/qaK56/33/

 
  • Order = {{test.value.order}} -> Key={{test.key}} Name=:{{test.value.name}}
myApp.controller('controller', ['$scope', function ($scope) { var testData = { a:{name:"CData", order: 2}, b:{name:"AData", order: 3}, c:{name:"BData", order: 1} }; $scope.testData = _.map(testData, function(vValue, vKey) { return { key:vKey, value:vValue }; }) ; $scope.sortMe = function() { return function(object) { return object.value.order; } } }]);

de acordo com http://docs.angularjs.org/api/ng.filter:orderBy , orderBy classifica uma matriz. No seu caso, você está passando um object, então você terá que implementar sua própria function de sorting.

ou passar um array –

 $scope.testData = { C: {name:"CData", order: 1}, B: {name:"BData", order: 2}, A: {name:"AData", order: 3}, } 

dê uma olhada em http://jsfiddle.net/qaK56/

Você deve realmente melhorar sua estrutura JSON para corrigir seu problema:

 $scope.testData = [ {name:"CData", order: 1}, {name:"BData", order: 2}, {name:"AData", order: 3}, ] 

Então você poderia fazer

 
  • ...
  • O problema, eu acho, é que as variables ​​(chave, valor) não estão disponíveis para o filtro orderBy, e você não deve armazenar dados em suas chaves de qualquer maneira

    Aqui está o que eu fiz e funciona.
    Eu usei apenas um object stringificado.

     $scope.thread = [ { mostRecent:{text:'hello world',timeStamp:12345678 } allMessages:[] } {MoreThreads...} {etc....} ] 

    se eu quisesse classificar por texto eu faria

     orderBy : 'mostRecent.text' 

    Resposta de Armin + uma verificação estrita para tipos de objects e chaves não angulares como $resolve

     app.filter('orderObjectBy', function(){ return function(input, attribute) { if (!angular.isObject(input)) return input; var array = []; for(var objectKey in input) { if (typeof(input[objectKey]) === "object" && objectKey.charAt(0) !== "$") array.push(input[objectKey]); } array.sort(function(a, b){ a = parseInt(a[attribute]); b = parseInt(b[attribute]); return a - b; }); return array; } }) 

    O seguinte permite a ordenação de objects por chave OU por uma chave dentro de um object .

    No modelo você pode fazer algo como:

      
  • Ou até mesmo:

      
  • O filtro:

     app.filter('orderObjectsBy', function(){ return function(input, attribute) { if (!angular.isObject(input)) return input; // Filter out angular objects. var array = []; for(var objectKey in input) { if (typeof(input[objectKey]) === "object" && objectKey.charAt(0) !== "$") array.push(input[objectKey]); } var attributeChain = attribute.split("."); array.sort(function(a, b){ for (var i=0; i < attributeChain.length; i++) { a = (typeof(a) === "object") && a.hasOwnProperty( attributeChain[i]) ? a[attributeChain[i]] : 0; b = (typeof(b) === "object") && b.hasOwnProperty( attributeChain[i]) ? b[attributeChain[i]] : 0; } return parseInt(a) - parseInt(b); }); return array; } }) 

    Vou adicionar minha versão atualizada do filtro, que suporta a próxima syntax:

     ng-repeat="(id, item) in $ctrl.modelData | orderObjectBy:'itemProperty.someOrder':'asc' 

     app.filter('orderObjectBy', function(){ function byString(o, s) { s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties s = s.replace(/^\./, ''); // strip a leading dot var a = s.split('.'); for (var i = 0, n = a.length; i < n; ++i) { var k = a[i]; if (k in o) { o = o[k]; } else { return; } } return o; } return function(input, attribute, direction) { if (!angular.isObject(input)) return input; var array = []; for(var objectKey in input) { if (input.hasOwnProperty(objectKey)) { array.push(input[objectKey]); } } array.sort(function(a, b){ a = parseInt(byString(a, attribute)); b = parseInt(byString(b, attribute)); return direction == 'asc' ? a - b : b - a; }); return array; } }) 

    Graças a Armin e Jason por suas respostas neste segmento, e Alnitak neste segmento .