diff --git a/src/ng/filter/orderBy.js b/src/ng/filter/orderBy.js index 93e6424d804e..57c374735d5d 100644 --- a/src/ng/filter/orderBy.js +++ b/src/ng/filter/orderBy.js @@ -40,6 +40,7 @@ * index: ... * } * ``` + * **Note:** `null` values use `'null'` as their type. * 2. The comparator function is used to sort the items, based on the derived values, types and * indices. * @@ -74,11 +75,15 @@ * * The default, built-in comparator should be sufficient for most usecases. In short, it compares * numbers numerically, strings alphabetically (and case-insensitively), for objects falls back to - * using their index in the original collection, and sorts values of different types by type. + * using their index in the original collection, sorts values of different types by type and puts + * `undefined` and `null` values at the end of the sorted list. * * More specifically, it follows these steps to determine the relative order of items: * - * 1. If the compared values are of different types, compare the types themselves alphabetically. + * 1. If the compared values are of different types: + * - If one of the values is undefined, consider it "greater than" the other. + * - Else if one of the values is null, consider it "greater than" the other. + * - Else compare the types themselves alphabetically. * 2. If both values are of type `string`, compare them alphabetically in a case- and * locale-insensitive way. * 3. If both values are objects, compare their indices instead. @@ -89,9 +94,10 @@ * * **Note:** If you notice numbers not being sorted as expected, make sure they are actually being * saved as numbers and not strings. - * **Note:** For the purpose of sorting, `null` values are treated as the string `'null'` (i.e. - * `type: 'string'`, `value: 'null'`). This may cause unexpected sort order relative to - * other values. + * **Note:** For the purpose of sorting, `null` and `undefined` are considered "greater than" + * any other value (with undefined "greater than" null). This effectively means that `null` + * and `undefined` values end up at the end of a list sorted in ascending order. + * **Note:** `null` values use `'null'` as their type to be able to distinguish them from objects. * * @param {Array|ArrayLike} collection - The collection (array or array-like object) to sort. * @param {(Function|string|Array.)=} expression - A predicate (or list of @@ -658,8 +664,7 @@ function orderByFilter($parse) { function getPredicateValue(value, index) { var type = typeof value; if (value === null) { - type = 'string'; - value = 'null'; + type = 'null'; } else if (type === 'object') { value = objectValue(value); } @@ -690,7 +695,11 @@ function orderByFilter($parse) { result = value1 < value2 ? -1 : 1; } } else { - result = type1 < type2 ? -1 : 1; + result = (type1 === 'undefined') ? 1 : + (type2 === 'undefined') ? -1 : + (type1 === 'null') ? 1 : + (type2 === 'null') ? -1 : + (type1 < type2) ? -1 : 1; } return result; diff --git a/test/ng/filter/orderBySpec.js b/test/ng/filter/orderBySpec.js index e8f0a4126eff..cab5cb678063 100644 --- a/test/ng/filter/orderBySpec.js +++ b/test/ng/filter/orderBySpec.js @@ -309,6 +309,16 @@ describe('Filter: orderBy', function() { expect(orderBy(items, expr)).toEqual(sorted); }); + + it('should consider null and undefined greater than any other value', function() { + var items = [undefined, null, 'z', {}, 999, false]; + var expr = null; + var sorted = [false, 999, {}, 'z', null, undefined]; + var reversed = [undefined, null, 'z', {}, 999, false]; + + expect(orderBy(items, expr)).toEqual(sorted); + expect(orderBy(items, expr, true)).toEqual(reversed); + }); }); describe('(custom comparator)', function() { @@ -376,7 +386,7 @@ describe('Filter: orderBy', function() { }); - it('should treat a value of `null` as `"null"`', function() { + it('should treat a value of `null` as type `"null"`', function() { var items = [null, null]; var expr = null; var reverse = null; @@ -386,8 +396,8 @@ describe('Filter: orderBy', function() { var arg = comparator.calls.argsFor(0)[0]; expect(arg).toEqual(jasmine.objectContaining({ - type: 'string', - value: 'null' + type: 'null', + value: null })); });