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

feat(orderBy): Add null and undefined at the end of the sorted list #16376

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
25 changes: 17 additions & 8 deletions src/ng/filter/orderBy.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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.
Expand All @@ -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.<Function|string>)=} expression - A predicate (or list of
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 13 additions & 3 deletions test/ng/filter/orderBySpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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;
Expand All @@ -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
}));
});

Expand Down