AngularJs sort object in ngRepeat

2020-02-25 07:41发布

I'm using AngularJs and found a problem in ordering properties of a hash object in a template.
My object is like:

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

Now, when I try to print these values in my template:

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

The order of the days printed is different: FRIDAY MONDAY THURSDAY TUESDAY WEDNESDAY

I tried to apply the filter orderBy but I think it doesn't work with objects, but just with arrays...

How can I order it?

5条回答
不美不萌又怎样
2楼-- · 2020-02-25 08:05

As per AngularJS docs (version 1.3.20):

You need to be aware that the JavaScript specification does not define what order it will return the keys for an object. In order to have a guaranteed deterministic order for the keys, Angular versions up to and including 1.3 sort the keys alphabetically.

A workaround is to use an array of keys:

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

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

Use the array in view for iteration:

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

Update from AngularJS version 1.4.6 docs:

Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser when running for key in myObj.

查看更多
家丑人穷心不美
3楼-- · 2020-02-25 08:05

This question is old, but I ended up coming up with an answer to this that I thought might be an improvement on some of the previous answers.

Rather than simply convert the object into an array, it's much more DRY to create an angular filter that does that for you, and then ngRepeat or ngOptions over that.

As an example:

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

Then, with an object like:

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

We could use it like so:

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

This way, you neither have to create a new array and pollute $scope, nor do you have to go back and change your actual degrees object, which could have unwanted side-effects.

查看更多
时光不老,我们不散
4楼-- · 2020-02-25 08:19

This was fixed in Angular 1.4. As stated in the official Angular documentation below:

Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser when running for key in myObj

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

查看更多
Ridiculous、
5楼-- · 2020-02-25 08:19

There is actually a simple solution ... The object keys are not ordered by default BUT if you create the object in browser from scratch your browser WILL know the order ;)

Example:

// 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"]

So simply ... recreate the object ... or use this simple filter:

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

Example with regular objects:

<!-- 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>

Example with sorted objects:

<!-- 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>
查看更多
\"骚年 ilove
6楼-- · 2020-02-25 08:20

There is no way to order hash objects like that. Not just in angular but in javascript in general.

I would convert the hash object to an array of objects, something like that:

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

And then change the view to something like that:

<div ng-repeat="day in week|orderBy:'day'">
    <span>{{day.day}}</span>
    <ul> <li ng-repeat="name in day.names">{{name}}</li> </ul>
</div>
查看更多
登录 后发表回答