【问题标题】:AngularJs sort object in ngRepeatngRepeat中的AngularJs排序对象
【发布时间】:2013-08-10 02:03:19
【问题描述】:

我正在使用 AngularJs,发现在模板中对哈希对象的属性进行排序时存在问题。
我的对象是这样的:

function TestCtrl($scope){
    $scope.week = {'MONDAY': ['manuel'], 'TUESDAY': [], 'WEDNESDAY': ['valerio'], 'THURSDAY': ['manuel', 'valerio'], 'FRIDAY': []}
}

现在,当我尝试在模板中打印这些值时:

<div ng-repeat="(day, names) in week">
    <span>{{day}}</span>
    <ul> <li ng-repeat="name in names">{{name}}</li> </ul>
</div>

打印的天数顺序不同:FRIDAY MONDAY THURSDAY TUESDAY WEDNESDAY

我尝试应用过滤器orderBy,但我认为它不适用于对象,而仅适用于数组...

如何订购?

【问题讨论】:

  • 我认为它与 angularjs 无关。默认情况下,对象键按字母顺序排序。
  • @CodeHater,它与 AngularJS 相关,不,对象键不会在 javascript 引擎中以任何方式排序。官方规范中唯一描述的是顺序不能保证,但是,所有浏览器都保持字符串对象键的顺序而不对其进行排序是事实上的标准。

标签: angularjs angularjs-ng-repeat


【解决方案1】:

根据 AngularJS docs(版本 1.3.20):

您需要注意 JavaScript 规范没有定义 它将以什么顺序返回对象的键。为了拥有一个 保证键的确定顺序,Angular 版本最高 并包括 1.3 按字母顺序对键进行排序

一种解决方法是使用键数组:

function TestCtrl($scope){
    $scope.week = {
        'MONDAY': ['manuel'], 'TUESDAY': [], 
        'WEDNESDAY': ['valerio'], 'THURSDAY': ['manuel', 'valerio'],    
        'FRIDAY': []}

    $scope.weekDays = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"];
}

使用视图中的数组进行迭代:

<div ng-repeat="day in weekDays">
    <span>{{day}}</span>
    <ul> <li ng-repeat="name in week[day]">{{name}}</li> </ul>
</div>

从 AngularJS 版本 1.4.6 更新 docs:

1.4 版删除了字母排序。我们现在依赖订单 运行for key in myObj时由浏览器返回。

【讨论】:

【解决方案2】:

没有办法像这样对哈希对象进行排序。不仅在 Angular 中,而且在一般的 javascript 中。

我会将散列对象转换为对象数组,如下所示:

$scope.week = [{day: 'MONDAY', names: ['manuel']}, {day: 'TUESDAY', names: []} ...];

然后将视图更改为类似的内容:

<div ng-repeat="day in week|orderBy:'day'">
    <span>{{day.day}}</span>
    <ul> <li ng-repeat="name in day.names">{{name}}</li> </ul>
</div>

【讨论】:

  • 再次,不是真的“一般来说,没有办法在 javascript 中对哈希对象 (...) 进行排序。”: Object.keys({day: 'MONDAY', names: ['manuel' ]}, {day: 'TUESDAY', names: []}) -> 返回 ["day", "names"]
  • 您建议的是一种解决方法(合法的),可以通过另一个数组对对象进行排序。无法对对象本身进行排序。
  • 你对我投了反对票吗?无论如何,我不建议对对象进行实际排序。 IMO 对象应呈现as is 而不对其进行排序。我想从 Angular 的源代码中删除这行代码:collectionKeys.sort();(我的代码只是一个演示)
  • 有一种方法可以订购一个对象......看看我的答案;)stackoverflow.com/questions/18124665/…
【解决方案3】:

这个问题很老了,但我最终想出了一个答案,我认为这可能是对以前的一些答案的改进。

与其简单地将对象转换为数组,不如先创建一个角度过滤器来为您执行此操作,然后再使用ngRepeatngOptions 进行处理。

举个例子:

angular.module('myproject')
    .filter('objOrder', function () {
        return function(object) {
            var array = [];
            angular.forEach(object, function (value, key) {
                array.push({key: key, value: value});
            });
            return array;
        };
    });

然后,像这样的对象:

    $scope.degrees: {
        ASC: "Associate's",
        BAS: "Bachelor's",
        MAS: "Master's",
        MD: "M.D.",
        JD: "J.D.",
        PHD: "Ph.D",
        OTH: "Other"
    }

我们可以这样使用它:

<select
    ng-model="myDegree"
    required
    ng-options="item.key as item.value for item in degrees | objOrder"
    >
</select>

这样,您既不必创建新数组并污染$scope,也不必返回并更改您的实际degrees 对象,这可能会产生不必要的副作用。

【讨论】:

  • 这不是一个可行的解决方案,因为过滤器总是返回一个新的数组实例,脏检查将进入不定式循环。
  • @FredYang 我在生产中使用了这种方法没有问题
【解决方案4】:

这已在 Angular 1.4 中修复。正如下面的官方 Angular 文档中所述:

1.4 版删除了字母排序。我们现在依赖订单 运行时浏览器返回for key in myObj

https://docs.angularjs.org/api/ng/directive/ngRepeat

【讨论】:

    【解决方案5】:

    其实有一个简单的解决方案... 如果您在浏览器中从头开始创建对象,则默认情况下对象键是不排序的

    例子:

    // test-1
    var data = {};
    data['a'] = 10;
    data['b'] = 5;
    data['c'] = 2;
    
    Object.keys(data); // ["a", "b", "c"]
    
    
    // test-2
    var data = {};
    data['b'] = 5;
    data['a'] = 10;
    data['c'] = 2;
    
    Object.keys(data); // ["b", "a", "c"]
    

    那么简单...重新创建对象...或使用这个简单的过滤器:

    .filter('orderObject', function () {
        return function (object, reverse) {
            var keys = Object.keys(object || {}).sort();
            if (reverse) keys.reverse();
            for (var ordered = {}, i = 0; keys[i]; i++) {
                ordered[keys[i]] = object[keys[i]];
            }
            return ordered;
        }
    })
    

    常规对象示例:

    <!-- MARKUP : DEFAULT -->
    <table>
        <tr ng-repeat="(key, value) in data">
            <td>{{key}}</td>
            <td>{{value}}</td>
        </tr>
    </table>
    
    <!-- RESULT : test-1 -->
    <table>
        <tr>
            <td>a</td>
            <td>10</td>
        </tr>
        <tr>
            <td>b</td>
            <td>5</td>
        </tr>
        <tr>
            <td>c</td>
            <td>2</td>
        </tr>
    </table>
    
    <!-- RESULT : test-2 -->
    <table>
        <tr>
            <td>b</td>
            <td>5</td>
        </tr>
        <tr>
            <td>a</td>
            <td>10</td>
        </tr>
        <tr>
            <td>c</td>
            <td>2</td>
        </tr>
    </table>
    

    排序对象示例:

    <!-- MARKUP : with FILTER orderObject:<reverse?> -->
    <table>
        <tr ng-repeat="(key, value) in data | orderObject">
            <td>{{key}}</td>
            <td>{{value}}</td>
        </tr>
    </table>
    
    <!-- RESULT : test-1 without reverse -->
    <table>
        <tr>
            <td>a</td>
            <td>10</td>
        </tr>
        <tr>
            <td>b</td>
            <td>5</td>
        </tr>
        <tr>
            <td>c</td>
            <td>2</td>
        </tr>
    </table>
    
    <!-- RESULT : test-2 with reverse -->
    <table>
        <tr>
            <td>c</td>
            <td>2</td>
        </tr>
        <tr>
            <td>b</td>
            <td>5</td>
        </tr>
        <tr>
            <td>a</td>
            <td>10</td>
        </tr>
    </table>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-13
      • 2018-06-01
      • 2019-06-12
      • 2013-01-03
      • 2013-06-11
      • 1970-01-01
      • 2013-06-10
      • 2013-12-13
      相关资源
      最近更新 更多