AngularJS按属性排序


93

我想做的是按属性对一些数据进行排序。这是我tought应该工作的示例,但事实并非如此。

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>

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

}]);

结果:

  1. A-> AData
  2. B-> BData
  3. C-> C数据

...恕我直言,应如下所示:

  1. C-> C数据
  2. B-> BData
  3. A-> AData

我是否错过了某些东西(可以在这里进行JSFiddle的实验)?

Answers:


148

AngularJS的orderBy过滤器仅支持数组-没有对象。因此,您必须编写自己的小型过滤器,该过滤器会为您进行排序。

或更改处理数据的格式(如果您对此有影响)。包含对象的数组可通过本机orderBy过滤器排序。

这是我的AngularJS的orderObjectBy过滤器:

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;
 }
});

您认为的用法:

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

在此示例中,对象需要一个position属性,但是您可以灵活地在对象中使用任何属性(包含整数),只需按照视图中的定义即可。

JSON示例:

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

这是一个小提琴,向您显示用法:http : //jsfiddle.net/4tkj8/1/


1
这很棒。我添加了对asc / desc进行排序的选项:app.filter('orderObjectBy',function(){返回函数(输入,属性,方向){如果(!angular.isObject(input))返回输入; var array = [] ; for(输入中的var objectKey){array.push(input [objectKey]);} array.sort(function(a,b){a = parseInt(a [attribute]); b = parseInt(b [attribute]) ; return direction =='asc'?a-b:b-a;}); return array;}}); 在HTML:<TR纳克重复= “VAL在清单| orderObjectBy: '支柱': 'ASC'”>
爵士风格

@Armin如果这是数组之类的对象怎么办?即{1:'Example 1', 2:'Example 2', 3:'Example 3', ...}
尤金2014年

8
很好的答案,但是我们以这种方式丢失了对象的密钥。要保留它,只需添加它即可在过滤器中创建新数组的行,例如,for(var objectKey in input) { input[objectKey]['_key'] = objectKey; array.push(input[objectKey]); }像我们可以使用的那样<div ng-repeat="value in object | orderObjectBy:'order'" ng-init="key = value['_key']">
Nicolas Janel 2014年

7
值得注意的是,Angular.js现在确实支持按对象数组中的属性进行排序... | orderBy: 'name'
Wildhoney

2
@Wildhoney这个问题是关于用键排序对象,而不是包含对象的数组。
阿明2015年

31

很简单,就这样做

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

ng-repeat="prop in props | orderBy:'order'"

33
这不适用于关联数组,这就是问题所在。
MFB

7

不要忘记parseInt()仅适用于Integer值。要对字符串值进行排序,您需要交换以下内容:

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

有了这个:

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

6

如您在angular-JS(https://github.com/angular/angular.js/blob/master/src/ng/filter/orderBy.js)的代码中所见,ng-repeat不适用于对象。这是一个带有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;
        }
    }
}]);

4

根据http://docs.angularjs.org/api/ng.filter:orderBy,orderBy对数组进行排序。在您的情况下,您要传递一个对象,因此您必须实现自己的排序功能。

或传递数组-

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

看看http://jsfiddle.net/qaK56/


我知道它可以与数组一起使用。所以解决方案是编写自己的排序函数?
PrimosK

您的jsfiddle!=您发布的代码。这是此处示例的正确jsfiddle:jsfiddle.net/qaK56/92
mrzmyr 2014年

3

您应该真正改善JSON结构以解决问题:

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

那你可以做

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

我认为问题是(key,value)变量不可用于orderBy过滤器,并且无论如何您都不应该在密钥中存储数据


2
告诉Firebase;)
MFB

据我所知,您在
Firebase中

如果将阵列存储在Firebase中,它将使用UID作为阵列的键。在许多情况下,您无法控制数据结构,因此您的建议可能有些笼统。
MFB

存储什么数组?一个人总是可以控制数据结构。OP还没有提及Firebase。
约书亚·伍沃德

2

这是我所做的,并且有效。
我只是使用一个字符串化的对象。

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

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

如果我想按文本排序,我会做

orderBy : 'mostRecent.text'

2

我将添加我的过滤器的升级版本,该版本能够支持下一个语法:

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;
        }
    })

感谢Armin和Jason在此主题中的回答,以及Alnitak在此主题中的回答。


1

Armin的答案+严格检查对象类型和非角度键,例如 $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

以下允许对象的排序由键 OR 由物体内的关键

在模板中,您可以执行以下操作:

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

甚至:

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

过滤器:

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;
 }
})

将objectList中的(k,i)的键转换为0和1是否正常?
肯·韦尔瓦特伦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.