Orderby not working with dict syntax on ng-repeat

29,376

Solution 1

The parameters to orderBy must match property names in an array of objects.

Your data needs to look something like this:

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

Then a filter like this will work:

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

Fiddle.

Note that orderBy works on the entire array (something in your sample code above) and it returns a sorted array. orderBy doesn't know anything about key and value.

Solution 2

this is not implemented. please see here:

https://github.com/angular/angular.js/issues/1286

EDIT (Aug 27, 2013): this issue seems to be resolved now.

Solution 3

I created a custom filter to make this possible for a select list:

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

the select list ng-options then reads as follows:

<select ng-options="kv.key as kv.value for kv in p.options | toDictionaryArray | orderBy:'value'"></select>

Solution 4

As akonsu says, the feature has been requested here. However, I still couldn't get it to work with the latest (1.3.0) beta.

There's a nice workaround buried in the comments (note this requires underscore, and you'll have to replace references to 'key' with 'value.$key' in the above example):

[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.

Solution 5

Here's a good work around (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});
      });
    }
  };
});
Share:
29,376
Admin
Author by

Admin

Updated on March 05, 2020

Comments

  • Admin
    Admin about 4 years

    I am trying to use ng-repeat with a dictionary style syntax and apply an order to the key value.

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

    It seems OrderBy isn't working as expected

    Example here http://jsfiddle.net/mhXuW/

  • Mark Rajcok
    Mark Rajcok over 11 years
    @akonsu, good point. I don't think it can be made to work with the dictionary syntax. I edited my answer somewhat.
  • Admin
    Admin over 11 years
    Thanks all, I am using underscore anyways so I fixed it with a the map function jsfiddle.net/PsrUY - That last point for me was the important bit. I was expecting angular to send through a new array with the structure that matches (key, value). Instead it was being based off the initial list
  • James Harrington
    James Harrington about 10 years
    My issue was i wasnt using quotes. <div ng-repeat="item in list | orderBy:'id'">
  • joseym
    joseym over 9 years
    While I'm not opposed to linking to a library that solves the problem, I am opposed to suggestion that the provided solution was taken and uncredited. The linked library does much more than my proposed solution.
  • Reactgular
    Reactgular over 9 years
    Why do you use defineProperty instead of val.$key = key?
  • Dunc
    Dunc over 9 years
    Good question - according to the author of that code (see link), "a simple change is to replace return Object.defineProperty(val, '$key', {proto: null, value: key}); with val.$key = key; return val;". So it seems you can use assignment, but you need to add a return statement.
  • Vikrant Yadav
    Vikrant Yadav about 7 years
    Hi, can you please tell me what's wrong in the following fiddle jsfiddle.net/mhXuW/73