ng-repeat directive sort the data when using (key, value)

Solution 1:

This is limitation of JavaScript not Angular.

From ECMAScript Third Edition:

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

From ECMAScript Language Specification

The [...] order of enumerating the properties [...] is not specified.

Angular sorts object keys explicitly in order to provide at least some sort of persistent behavior.

Workaround is to iterate over 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
};

Solution 2:

EDIT: I've filed a bug, feel free to +1

ECMAScript does not specify order in which keys should be iterated, however all major browsers implement objects as linked hash map (preserves order) and a lot of js libraries depend on this behavior and so we've got used to it and it's hardly going to change.

Angular on the other hand (which is totally unexpected) sort it alphabetically. I've inspected the source code myself, it is hard-coded there and it would be nice if it got resolved one day. Otherwise the (k, v) in obj feature is completely useless.

You really cant do anything with that, tricking angular to think your result is an array is not useful for anything, because you would need numeric keys then...

If this is okay, you can define getter for length:

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

Otherwise you'll need some kind of filter which will iterate object using for(var k in obj) and store result in array.

Solution 3:

There is actually an answer: it's called orderBy and 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 might need an index to know set order

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

Solution 4:

This is fixed as of Angular 1.4.

See details here:

Previously, the order of items when using ngRepeat to iterate over object properties was guaranteed to be consistent by sorting the keys into alphabetic order.

Now, the order of the items is browser dependent based on the order returned from iterating over the object using the for key in obj syntax.

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