50

Suppose I have the following users:

$scope.users = {
  "2": {
    email: 'john@gmail.com',
    name: 'John'
  },
  "3": {
    email: 'elisa@gmail.com',
    name: 'Elisa'
  }
}

I would like to create a <select> with the following options:

<option value="3">Elisa</option>
<option value="2">John</option>

In other words, users should be sorted by name.

I tried the following using the (key, value) in expression syntax, but it doesn't work:

<option ng-repeat="(user_id, user) in users | orderBy:'user.name'" 
        value="{{ user.id }}">
  {{ user.name }}
</option>

Live example here.

What am I missing?

Please do not suggest solutions with ng-options as I use ui-select2 which is incompatible with ng-options.

Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746
  • We don't need two new tags for this question and this question only. Please do the tags a favor by adding an appropriate wiki and adding them to other relevant questions. If you can't find other questions for the tags, then they don't need to exist twice over... – Charles Feb 21 '13 at 09:23
  • 2
    `ng-repeat` and `orderBy` are very common things in AngularJS. I believe there will be much more questions regarding these two. But ,anyway, I added these tags to some other questions. – Misha Moroshko Feb 21 '13 at 10:01
  • Since I lack the reputation to formally suggest tag alternate spellings, someone else on here should add **angularjs-order-by**. It seems nonsensical that the camel cased `ngRepeat` would become `ng-repeat`, while `orderBy` becomes `orderby`. – maurice Jun 15 '15 at 16:57
  • A simple example : http://goo.gl/XYmwkr – Suresh Kamrushi Mar 03 '16 at 13:15
  • https://stackoverflow.com/questions/16261348/descending-order-by-date-filter-in-angularjs/58565750#58565750 – Abdo-Host Oct 25 '19 at 23:36

3 Answers3

56

While you would see this in the thread the author's answer references in a link, I thought it would be good to put up one of the mentioned workarounds up on SO:

It is true that this is technically not implemented, but there is an easy work around if you're willing to change your data model slightly: use a custom filter to generate an array of the object's properties (without replacement). If you add the key field to the objects ("id" in the above case), you should be able to get the behavior your looking for:

app.filter("toArray", function(){
    return function(obj) {
        var result = [];
        angular.forEach(obj, function(val, key) {
            result.push(val);
        });
        return result;
    };
});
...

$scope.users = {
    1: {name: "John", email: "john@gmail.com", id: 1},
    2: {name: "Elisa", email: "elisa@gmail.com", id: 2}
};

Here's the ng-repeat directive that could be used:

<option value="{{user.id}}" ng-repeat="user in users | toArray | orderBy:'name'">{{user.name}}</option>

And here's the plunkr.

Notice that the orderBy filter takes name as its parameter and not user.name.

Unfortunately, adding the id property to your objects does create potential for mismatch with it's key in the containing object.

In the link you mentioned in your answer, there are also proposed solutions that create the id property in the user objects on the fly, but I feel like this approach is a little less messy (at the cost of introducing data replication).

Andresch Serj
  • 35,217
  • 15
  • 59
  • 101
mhess
  • 1,364
  • 14
  • 12
  • @BarthZalewski This looks good however how come if I try to reverse the filter nothing changes? can you handle reverse i n cuh as a situation? ng-repeat="user in users | toArray | orderBy:'name' : reverse" – ak85 Feb 22 '15 at 07:46
  • This works too when using the (key, value) in users approach too. Well done! – Robbie Smith Oct 09 '15 at 13:44
  • 1
    In response to @ak85's question you would use ng-repeat="user in users | toArray | orderBy:'name' : true" to reverse the list. Boolean true identifies a reverse order. – Doug Mar 13 '16 at 01:43
9

OK, I found the answer:

It is not implemented yet :(

Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746
  • 9
    It might also be worth mentioning that there are no plans to implement it either according to the thread you cite. – mhess Nov 06 '13 at 08:38
0

Adding to the accepted answer and seeing your data format, you should transform your data as

app.filter('myFilterUsers',function(){
    return function(data)
    {
        var newRes = [];
        angular.forEach(data,function(val,key){
            val["id"] = key;  //Add the ID in the JSON object as you need this as well.
            newRes.push(val);
        });
        return newRes;
    }
});
Saksham
  • 9,037
  • 7
  • 45
  • 73