Skip to content

Commit 8bfeddb

Browse files
committed
fix(orderBy): maintain order in array of objects when predicate is not provided
In ES262, there are two properties which are used to get a primitive value from an Object: - valueOf() -- a method which returns a primitive value represented by the Object - toString() -- a method which returns a string value representing the Object. When comparing objects using relational operators, the abstract operation ToPrimitive(O, TypeHint) is used, which will use these methods to retrieve a value. This CL emulates the behaviour of ToPrimitive(), and ensures that no ordering occurs if the retrieved value is identical. This behaviour was previously used for Date objects, however it can be safely made generic as it applies to all objects. Closes angular#9566 Closes angular#9747 Closes angular#10311
1 parent 015111f commit 8bfeddb

File tree

2 files changed

+44
-5
lines changed

2 files changed

+44
-5
lines changed

src/ng/filter/orderBy.js

+22-5
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,29 @@ function orderByFilter($parse) {
163163
function compare(v1, v2) {
164164
var t1 = typeof v1;
165165
var t2 = typeof v2;
166-
if (t1 == t2) {
167-
if (isDate(v1) && isDate(v2)) {
168-
v1 = v1.valueOf();
169-
v2 = v2.valueOf();
166+
// Prepare values for Abstract Relational Comparison
167+
// (http://www.ecma-international.org/ecma-262/5.1/#sec-11.8.5):
168+
// If the resulting values are identical, return 0 to prevent
169+
// incorrect re-ordering.
170+
if (t1 === t2 && t1 === "object") {
171+
// If types are both numbers, emulate abstract ToPrimitive() operation
172+
// in order to get primitive values suitable for comparison
173+
t1 = typeof (v1 = v1.valueOf());
174+
t2 = typeof (v2 = v2.valueOf());
175+
if (t1 === t2 && t1 === "object") {
176+
// Object.prototype.valueOf will return the original object, by
177+
// default. If we do not receive a primitive value, use ToString()
178+
// instead.
179+
t1 = typeof (v1 = v1.toString());
180+
t2 = typeof (v2 = v2.toString());
181+
182+
// If the end result of toString() for each item is the same, do not
183+
// perform relational comparison, and do not re-order objects.
184+
if (t1 === t2 && v1 === v2) return 0;
170185
}
171-
if (t1 == "string") {
186+
}
187+
if (t1 === t2) {
188+
if (t1 === "string") {
172189
v1 = v1.toLowerCase();
173190
v2 = v2.toLowerCase();
174191
}

test/ng/filter/orderBySpec.js

+22
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,17 @@ describe('Filter: orderBy', function() {
104104
return orderBy([{"Tip %": .15}, {"Tip %": .25}, {"Tip %": .40}], '"Tip %\'');
105105
}).toThrow();
106106
});
107+
108+
109+
it('should not reverse array of objects with no predicate', function() {
110+
var array = [
111+
{ id: 2 },
112+
{ id: 1 },
113+
{ id: 4 },
114+
{ id: 3 }
115+
];
116+
expect(orderBy(array)).toEqualData(array);
117+
});
107118
});
108119

109120

@@ -210,5 +221,16 @@ describe('Filter: orderBy', function() {
210221
return orderBy([{"Tip %": .15}, {"Tip %": .25}, {"Tip %": .40}], '"Tip %\'');
211222
}).toThrow();
212223
});
224+
225+
226+
it('should not reverse array of objects with no predicate', function() {
227+
var array = [
228+
{ id: 2 },
229+
{ id: 1 },
230+
{ id: 4 },
231+
{ id: 3 }
232+
];
233+
expect(orderBy(array)).toEqualData(array);
234+
});
213235
});
214236
});

0 commit comments

Comments
 (0)