I would like to use the orderBy filter with the ng-repeat directive while iterating over an objects properties. As the orderBy filter only works with Array, the Angular doc suggests to use the toArray filter.
The toArray filter works like a charm with object-properties like:
var obj = {
a: { name: 'A' },
b: { name: 'B' },
c: { name: 'C' }
};
But it causes an infinite digest loop when used with non-object properties:
var obj = {
a: 'A',
b: 'B',
c: 'C'
};
Here is a plunker illustrating the issue.
You should not do that anyway, filters are generally bad idea when transforming data, cos it will get recalculated every time digest cycle makes a loop. Your plunker does not work, so it is hard to say why, but looking at code I would say that it does make completly new array with each digest loop, and in case of objects it adds $key property, which helps stoping digest cycle. It cannot add such property to strings. But I'm not really sure about that.
Edit: when you add console.log to toArray:
return Object.keys(obj).map(function (key) {
var value = obj[key];
console.log(key, value);
return angular.isObject(value) ?
Object.defineProperty(value, '$key', { enumerable: false, value: key}) :
{ $key: key, $value: value };
});
In logs you can see answer to your question:
VM596 angular-toArrayFilter.js:15 b b
VM596 angular-toArrayFilter.js:15 a a
VM596 angular-toArrayFilter.js:15 c Object {p: "c"}
VM596 angular-toArrayFilter.js:15 b Object {p: "b"}
VM596 angular-toArrayFilter.js:15 a Object {p: "a"}
VM596 angular-toArrayFilter.js:15 c Object {p: "c", $key: "c"}
VM596 angular-toArrayFilter.js:15 b Object {p: "b", $key: "b"}
VM596 angular-toArrayFilter.js:15 a Object {p: "a", $key: "a"}
VM596 angular-toArrayFilter.js:15 c c
VM596 angular-toArrayFilter.js:15 b b
VM596 angular-toArrayFilter.js:15 a a
VM596 angular-toArrayFilter.js:15 c Object {p: "c", $$hashKey: "object:11", $key: "c"}
VM596 angular-toArrayFilter.js:15 b Object {p: "b", $$hashKey: "object:10", $key: "b"}
VM596 angular-toArrayFilter.js:15 a Object {p: "a", $$hashKey: "object:9", $key: "a"}
In case objects, angular is using the same objects and does not create new ones. So that it can assume that array did not change and end digest cycle. In case of string values it creates new objects each time filter is run, so that it assumes that each time different array is created, so that it cannot end digest cycle.