Ng-repeat directive sorts data when used (key, value)

I have code like this with ng-repeat = "(key, value) in data." In the controller:

$scope.Dates = {"Today":"30", "This Week":"42", "This Month": "Oct", "This Quarter" : "Bad", "This Year" : 2013 } 

and ng-repeat as

 <div ng-repeat="(key,value) in Dates"> {{key}} ==> {{value}} </div> 

The output is sorted as

 This Month ==> Oct This Quarter ==> Bad This Week ==> 42 This Year ==> 2013 Today ==> 30 

How to get rid of this sorting is (weird) since I want the keys to be used in the code. I checked the google group, but there was a fiddle to use two arrays in which the key value was stored. http://jsfiddle.net/Saulzar/puhML/3/b . Do not want to go with this approach.

+48
angularjs
Oct 30 '13 at 7:55
source share
7 answers

This is a limitation of JavaScript not Angular.

From Third Edition of ECMAScript :

4.3.3 An object is a member of type Object. This is an unordered collection of properties, each of which contains a primitive value, object, or function. The function stored in the property of an object is called a method.

From ECMAScript Language Specification

The order [...] of listing properties [...] is not specified .

Angular explicitly sorts object keys to ensure at least some kind of persistent behavior.

The workaround is to iterate over the extracted keys:

 <div ng-repeat="key in keys(Dates)"> {{key}} ==> {{Dates[key]}} </div> 
 $scope.keys = function(obj){ return obj? Object.keys(obj) : []; } $scope.Dates = { "Today":"30", "This Week":"42", "This Month": "Oct", "This Quarter" : "Bad", "This Year" : 2013 }; 
+65
Oct 30 '13 at 8:23
source share

EDIT: I filed an error , don't be shy +1

ECMAScript does not indicate the order in which keys should be iterated, however, all major browsers implement objects as a related hash map (preserves order), and many js libraries depend on this behavior, and therefore we are used to it, and this is unlikely to change.

Angular on the other hand (this is completely unexpected ) sorts it alphabetically. I myself checked the source code, it is hardcoded, and it would be nice if it were resolved one day. Otherwise, the function (k, v) in obj completely useless .

You really can't do anything with this, tricking angular to think that your result - an array is not useful for anything, because then you will need the number keys ...

If this is normal, you can define a getter for the length:

 Object.defineProperty(yourResultObjectOrPrototype, 'length', { get: function(){ return Object.keys(this).length; } }) 

Otherwise, you will need some kind of filter that will iterate over the object using for(var k in obj) and save the result in an array.

+9
Feb 11 '14 at 10:33
source share

Actually there is an answer: it is called orderBy, not sort:

https://docs.angularjs.org/api/ng/filter/orderBy

{{ orderBy_expression | orderBy : expression : reverse}}

 <tr ng-repeat="friend in friends | orderBy:'-age'"> <td>{{friend.name}}</td> <td>{{friend.phone}}</td> <td>{{friend.age}}</td> </tr> 

Your list just needs to be a list, and you may need an index to find out the order of typing

 $scope.Dates = [{index:1, "Today":"30"}, {index:2,"This Week":"42"}, {index:3,"This Month": "Oct"}, {index:4,"This Quarter" : "Bad"}, {index:5,"This Year" : 2013}] 

and then

 <tr ng-repeat="(key, value) in Dates | orderBy:'index'"> <td>{{key}}</td> <td>{{value}}</td> </tr> 
+7
Apr 23 '15 at 23:59 on
source share

This is fixed with Angular 1.4 .

More details here :

Previously, the order of elements when using ngRepeat to iterate over the properties of an object was guaranteed to be consistent by sorting the keys in alphabetical order.

Now the order of the elements depends on the browser depending on the order returned from iterating over the object using the syntax for key in obj .

It seems that browsers usually follow a strategy of providing keys in the order in which they were defined ...

+6
Jul 07 '15 at 19:55
source share

I managed to sort the Object of Strings by key in alphabetical order like this with ng-repeat!

In my controller:

 $scope.build_config = { build_path : "/x/eng/build", arch : "x86", variant : "debug", run_method : "boot", }; $scope.get_keys = function (obj) { if (obj) return Object.keys(obj); }; 

In my HTML:

 <tr ng-repeat="key in get_keys(build_config) | orderBy:'toString()'"> <td> {{key}} </td> <td> {{selected.build_config[key]}} </td> </tr> 
+2
Apr 7 '16 at 20:55 on
source share

Object.keys does not reserve an order - FYI https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

// array as an object with random ordering of keys

 var an_obj = { 100: 'a', 2: 'b', 7: 'c' }; console.log(Object.keys(an_obj)); // console: ['2', '7', '100'] 

I convert it to an array of object

 $scope.Dates = [ { id: "Today", value:"30" }, { id: "This Week", value:"42" }, { id: "This Month", value: "Oct" }, { id: "This Quarter", value : "Bad" }, { id: "This Year", value : 2013 } ]; <li ng-repeat="date in Dates">{{date.id}} -> {{date.value}}</li> 

http://jsfiddle.net/2hqew68k/1/

+1
Apr 19 '16 at 18:10
source share

Well, as explained in the Angular documentation for ngRepeat

https://docs.angularjs.org/api/ng/directive/ngRepeat#iterating-over-object-properties

when used to iterate over the properties of an object, it will not work

The built-in orderBy filters and the filter do not work with objects, and throws an error if used with one.

The best solution in this case, I believe that it uses arrays instead of the object and its properties. Therefore, just convert it to an array, iterate over the properties of your object and, for example, click on a new array. In the end, I think it would be a natural choice for a collection, and not for a single object with many properties.

0
May 19 '17 at 7:09 a.m.
source share



All Articles