AngularJS Tri par propriété

ce que j'essaie de faire, c'est trier des données par propriétés. Voici un exemple que j'ai pensé devoir fonctionner mais qui ne fonctionne pas.

partie HTML:

<div ng-app='myApp'>
    <div ng-controller="controller">
    <ul>
        <li ng-repeat="(key, value) in testData | orderBy:'value.order'">
            {{value.order}}. {{key}} -> {{value.name}}
        </li>
    </ul>
    </div>
</div>

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

}]);

et le résultat:

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

... que mon humble avis devrait ressembler à ceci:

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

ai-je manqué quelque chose (voici prêt JSFiddle à expérimenter sur)?

87
demandé sur PrimosK 2013-01-23 15:02:24

10 réponses

AngularJS' orderBy filter ne supporte que les tableaux - pas d'objets. Donc, vous devez écrire un petit filtre, qui fait le tri pour vous.

ou modifier le format des données que vous manipulez (si vous avez de l'influence sur ce format). Un tableau contenant des objets est sortable par native orderBy filter.

Voici mon orderObjectBy filtre pour 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;
 }
});

Utilisation de votre point de vue:

<div class="item" ng-repeat="item in items | orderObjectBy:'position'">
    //...
</div>

l'objet a besoin dans cet exemple d'un attribut de position, mais vous avez la flexibilité d'utiliser n'importe quel attribut dans les objets (contenant un entier), juste par définition en vue.

exemple JSON:

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

voici un violon qui vous montre l'usage: http://jsfiddle.net/4tkj8/1 /

142
répondu Armin 2015-03-31 16:17:46

c'est assez facile, faites - le comme ça

$scope.props = [{order:"1"},{order:"5"},{order:"2"}]

ng-repeat="prop in props | orderBy:'order'"
31
répondu Leon 2013-12-05 11:07:01

N'oubliez pas que parseInt() ne fonctionne que pour des valeurs entières. Pour trier les valeurs des chaînes de caractères, vous devez échanger ceci:

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

avec ceci:

array.sort(function(a, b){
  var alc = a[attribute].toLowerCase(),
      blc = b[attribute].toLowerCase();
  return alc > blc ? 1 : alc < blc ? -1 : 0;
});
6
répondu Eric Steinborn 2013-09-05 17:22:29

comme vous pouvez le voir dans le code d'angular-JS ( https://github.com/angular/angular.js/blob/master/src/ng/filter/orderBy.js ) ng-repeat ne fonctionne pas avec les objets. Voici un hack avec sortFunction.

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

<div ng-app='myApp'>
    <div ng-controller="controller">
    <ul>
        <li ng-repeat="test in testData | orderBy:sortMe()">
            Order = {{test.value.order}} -> Key={{test.key}} Name=:{{test.value.name}}
        </li>
    </ul>
    </div>
</div>

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;
        }
    }
}]);
5
répondu SunnyShah 2013-01-23 13:16:07

selon http://docs.angularjs.org/api/ng.filter:orderBy , orderBy trie un tableau. Dans votre cas, vous passez un objet, vous devrez donc mettre en œuvre votre propre fonction de tri.

ou passer un tableau -

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

regardez http://jsfiddle.net/qaK56 /

3
répondu Gal Ben-Haim 2013-01-23 12:22:53

vous devriez vraiment améliorer votre structure JSON pour résoudre votre problème:

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

Ensuite, vous pouvez faire

<li ng-repeat="test in testData | orderBy:order">...</li>

le problème, je pense, est que les variables (clé, valeur) ne sont pas disponibles pour le filtre orderBy, et vous ne devriez pas stocker des données dans vos clés de toute façon

3
répondu Joshua Wooward 2014-04-17 23:01:29

Voici ce que j'ai fait et ça fonctionne.

Je viens d'utiliser un objet stringifié.

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

<div ng-repeat="message in thread | orderBy : '-mostRecent.timeStamp'" >

si je voulais trier par texte, je ne

orderBy : 'mostRecent.text'
2
répondu James Harrington 2014-09-24 16:30:48

Armin réponse + un contrôle strict pour les types d'objets et de non-angulaire clés tels que $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;
 }
})
1
répondu dipole_moment 2015-08-07 15:48:01

ce qui suit permet l'ordre des objets par la clé ou par une clé à l'intérieur d'un objet .

dans le modèle, vous pouvez faire quelque chose comme:

    <li ng-repeat="(k,i) in objectList | orderObjectsBy: 'someKey'">

Ou encore:

    <li ng-repeat="(k,i) in objectList | orderObjectsBy: 'someObj.someKey'">

le filtre:

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;
 }
})
1
répondu dipole_moment 2016-01-17 00:06:53

je vais ajouter ma version améliorée de filter qui peut prendre en charge la syntaxe suivante:

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

app.filter('orderObjectBy', function(){

         function byString(o, s) {
            s = s.replace(/\[(\w+)\]/g, '.'); // 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;
        }
    })

merci à Armin et Jason pour leurs réponses dans ce fil, et Alnitak dans ce fil .

1
répondu TachikomaGT 2017-05-23 12:34:38