Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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?

share|improve this question
    
I dont think its related to angularjs. The object keys get sorted alphabetically by default. –  CodeHater Aug 8 '13 at 11:20
    
@CodeHater, it is related to AngularJS and no, object keys won't be sorted in any way in javascript engines. The only thing described in the official spec is that the order can not be guaranteed, but however, it is a de-facto standard that all browsers keep the order of string object keys and don't sort it. –  Marc J. Schmidt Aug 26 '14 at 18:47

4 Answers 4

up vote 13 down vote accepted

JS Object keys get sorted alphabetically by default. If you don't want to change your source object then you can use another array to store the order and loop over that instead:

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>
share|improve this answer
2  
"JS Object keys get sorted alphabetically by default ": This is not true. AngularJS does the sort: github.com/angular/angular.js/blob/master/src/ng/directive/… –  Marc J. Schmidt Aug 26 '14 at 18:36
    
True to that, @MArc, there's also a lot of debate trying to remove this 'feature': github.com/angular/angular.js/issues/6210 –  Adit Saxena Aug 29 '14 at 10:49

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>
share|improve this answer
    
Again, not true "There is no way to order hash objects (...) in javascript in general.": Object.keys({day: 'MONDAY', names: ['manuel']}, {day: 'TUESDAY', names: []}) -> returns ["day", "names"] –  Adit Saxena Aug 29 '14 at 11:02
    
What you're suggesting is a workaround (a legit one) to order objects via another array. There is no way to order the objects themselves. –  Shay Friedman Aug 31 '14 at 7:24
    
did you downvote me? Anyway I did not suggest to actually sort objects. IMO the object should be presented as is without sorting it. I'd like to remove this line of code from Angular's source code: collectionKeys.sort(); (my code was just a demonstration) –  Adit Saxena Sep 23 '14 at 12:11

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.

share|improve this answer
    
This is not a workable solution, because the filter always return a new instance of array, the dirty checking will go into infinitive loop. –  Fred Yang Jan 26 at 21:37
    
@FredYang I have used this method in production without issue –  jdotjdot Jan 26 at 21:46

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

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.