在ng-repeat中使用字典语法时,orderby无法正常工作

39

我正在尝试使用类似字典的语法来使用ng-repeat,同时对键值进行排序。

(key, value) in something | orderBy:'key'

但是似乎OrderBy没有按照预期工作。

这里有个示例: http://jsfiddle.net/mhXuW/

6个回答

19

orderBy的参数必须与对象数组中的属性名称匹配。

您的数据应该长这样:

$scope.list2 = [ { id:"2013-01-08T00:00:00", name:'Joe'},
                 { id:"2013-01-09T00:00:00", name:'Sue'}];

那么这样的筛选器将起作用:

<div ng-repeat="item in list2 | orderBy:'id':true">

Fiddle

请注意,orderBy作用于整个数组(在您的示例代码中为something),并返回已排序的数组。 orderBy对于keyvalue一无所知。


@akonsu,说得好。我认为这无法使用字典语法来实现。我对我的回答进行了一些编辑。 - Mark Rajcok
2
谢谢大家,不管怎样我正在使用underscore,所以我用映射函数修复了它。http://jsfiddle.net/PsrUY/ - 对我而言,最后一个问题是关键点。我原本期望Angular发送一个新的数组,并具有与(键,值)相匹配的结构。但实际上它是基于初始列表。 - user818677
1
我的问题是我没有使用引号。 <div ng-repeat="item in list | orderBy:'id'"> - James Harrington
你好,请问以下fiddle http://jsfiddle.net/mhXuW/73/有什么问题? - Vikrant Yadav

11

7
我创建了一个自定义过滤器,使得选择列表可以实现这一功能:
.filter('toDictionaryArray', function () {
    return function (obj) {
        if (!(obj instanceof Object)) return obj;

        var arr = [];
        for (var key in obj) {
            arr.push({ key: key, value: obj[key] });
        }
        return arr;
    }
})

选择列表 ng-options 的读法如下:
<select ng-options="kv.key as kv.value for kv in p.options | toDictionaryArray | orderBy:'value'"></select>

2
如akonsu所说,这个功能已经在这里被请求。然而,我仍然无法在最新的(1.3.0)beta版本中让它工作。
有一个不错的解决方法被埋藏在评论中(请注意,这需要underscore,并且你将不得不在上面的示例中用'value.$key'替换对'key'的引用)。

[Add a filter]:

app.filter('toArray', function() { return function(obj) {
    if (!(obj instanceof Object)) return obj;
    return _.map(obj, function(val, key) {
        return Object.defineProperty(val, '$key', {__proto__: null, value: key});
    });
}});

Example markup:

<div ng-repeat="val in object | toArray | orderBy:'priority' | filter:fieldSearch">
  {{val.$key}} : {{val}} 
</div>

Potential downsides:

  • Object.defineProperty will not work like this in IE8 (if you don't mind making $key enumerable then this is an easy change).
  • If your property values are not objects then you can't set the $key property and this fails.
  • It is not directly integrated into orderBy or ngRepeat so the syntax is different.

1
你为什么使用defineProperty而不是val.$key = key - Reactgular
1
好问题 - 根据那段代码的作者(请参见链接),"一个简单的更改是将 return Object.defineProperty(val, '$key', {proto: null, value: key}); 替换为 val.$key = key; return val;"。因此,似乎您可以使用赋值,但需要添加一个返回语句。 - Dunc

2

这里有一个好的解决方法(angular-toArrayFilter):

.filter('toArray', function () {
  return function (obj, addKey) {
    if ( addKey === false ) {
      return Object.keys(obj).map(function(key) {
        return obj[key];
      });
    } else {
      return Object.keys(obj).map(function (key) {
        if(typeof obj[key] == 'object') return Object.defineProperty(obj[key], '$key', {     enumerable: false, value: key});
      });
    }
  };
});

虽然我不反对链接到解决问题的库,但我反对暗示提供的解决方案被采纳却没有给予信用。链接的库比我的建议解决方案做得更多。 - joseym

0

不要使用只支持数组而不支持对象的 orderby 过滤器。你可以像这样编写自己的过滤器,我从 Justin Klemm http://justinklemm.com/angularjs-filter-ordering-objects-ngrepeat/ 处获取了代码,并添加了支持指定多个排序字段的功能。下面是一个用于根据值中的属性进行过滤的过滤器示例,但你也可以轻松地将其更改为根据键进行过滤。

app.filter('orderObjectBy', function()
{
    return function(items, fields, reverse)
    {
        var filtered = [];
        angular.forEach(items, function(item)
        {
            filtered.push(item);
        });

        filtered.sort(function (a, b)
        {
            var result = 0;

            for (var i = 0; i < fields.length; ++i)
            {
                if (a[fields[i]] > b[fields[i]])
                {
                    result = 1;
                    break;
                }
                else if (a[fields[i]] < b[fields[i]])
                {
                    result = -1;
                    break;
                }
            }

            return result;
        });

        if (reverse)
        {
            filtered.reverse();
        }

        return filtered;
    };
});

然后在您的HTML5网页中使用它,其中statistics是一个具有键值对的映射/字典。

<div class="row" ng-repeat="stat in statistics | orderObjectBy: 'NumTimesPartnered', 'NumTimesOpponent']:true">
    <div class="col col-33">{{stat.Name}}</div>
    <div class="col"><center>{{stat.NumTimesPartnered}}</center></div>
    <div class="col"><center>{{stat.NumTimesOpponent}}</center></div>
</div>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接