Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

fix(orderBy): do not try to call valueOf/toString on null #10386

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 27 additions & 19 deletions src/ng/filter/orderBy.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,29 +160,37 @@ function orderByFilter($parse) {
? function(a, b) {return comp(b,a);}
: comp;
}

function isPrimitive(value) {
switch (typeof value) {
case 'number': /* falls through */
case 'boolean': /* falls through */
case 'string':
return true;
default:
return false;
}
}

function objectToString(value) {
if (value === null) return 'null';
if (typeof value.toString === 'function') {
value = value.toString();
if (isPrimitive(value)) return value;
}
if (typeof value.valueOf === 'function') {
value = value.valueOf();
if (isPrimitive(value)) return value;
}
return '';
}

function compare(v1, v2) {
var t1 = typeof v1;
var t2 = typeof v2;
// Prepare values for Abstract Relational Comparison
// (http://www.ecma-international.org/ecma-262/5.1/#sec-11.8.5):
// If the resulting values are identical, return 0 to prevent
// incorrect re-ordering.
if (t1 === t2 && t1 === "object") {
// If types are both numbers, emulate abstract ToPrimitive() operation
// in order to get primitive values suitable for comparison
t1 = typeof (v1.valueOf ? v1 = v1.valueOf() : v1);
t2 = typeof (v2.valueOf ? v2 = v2.valueOf() : v2);
if (t1 === t2 && t1 === "object") {
// Object.prototype.valueOf will return the original object, by
// default. If we do not receive a primitive value, use ToString()
// instead.
t1 = typeof (v1.toString ? v1 = v1.toString() : v1);
t2 = typeof (v2.toString ? v2 = v2.toString() : v2);

// If the end result of toString() for each item is the same, do not
// perform relational comparison, and do not re-order objects.
if (t1 === t2 && v1 === v2 || t1 === "object") return 0;
}
v1 = objectToString(v1);
v2 = objectToString(v2);
}
if (t1 === t2) {
if (t1 === "string") {
Expand Down
32 changes: 32 additions & 0 deletions test/ng/filter/orderBySpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,22 @@ describe('Filter: orderBy', function() {
});
expect(orderBy(array)).toEqualData(array);
});


it('should sort nulls as Array.prototype.sort', function() {
var array = [
{ id: 2 },
null,
{ id: 3 },
null
];
expect(orderBy(array)).toEqualData([
{ id: 2 },
{ id: 3 },
null,
null
]);
});
});


Expand Down Expand Up @@ -252,5 +268,21 @@ describe('Filter: orderBy', function() {
});
expect(orderBy(array)).toEqualData(array);
});


it('should sort nulls as Array.prototype.sort', function() {
var array = [
{ id: 2 },
null,
{ id: 3 },
null
];
expect(orderBy(array)).toEqualData([
{ id: 2 },
{ id: 3 },
null,
null
]);
});
});
});