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

Commit 2a85a63

Browse files
nhodgesgkalpak
authored andcommitted
fix(orderByFilter): throw error if input is not array-like
BREAKING CHANGE: Previously, an non array-like input would pass through the orderBy filter unchanged. Now, an error is thrown. This can be worked around by converting an object to an array, either manually or using a filter such as https://github.com/petebacondarwin/angular-toArrayFilter. (`null` and `undefined` still pass through without an error, in order to support asynchronous loading of resources.) Closes #11255 Closes #11719
1 parent 00d2b2c commit 2a85a63

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-2
lines changed
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
@ngdoc error
2+
@name orderBy:notarray
3+
@fullName Value is not array-like
4+
@description
5+
6+
This error occurs when {@link ng.orderBy orderBy} is not passed an array-like value:
7+
```html
8+
<div ng-repeat="(key, value) in myObj | orderBy:someProp">
9+
{{ key }} : {{ value }}
10+
</div>
11+
```
12+
13+
`orderBy` must be used with an array-like value so a subset of items can be returned.
14+
The array can be initialized asynchronously and therefore `null` or `undefined` won't throw this error.
15+
16+
To use `orderBy` to order the properties of an object, you can create your own array based on that object:
17+
```js
18+
angular.module('aModule', [])
19+
.controller('aController', function($scope) {
20+
var myObj = {
21+
one: {id: 1, name: 'Some thing'},
22+
two: {id: 2, name: 'Another thing'},
23+
three: {id: 3, name: 'A third thing'}
24+
};
25+
26+
$scope.arrFromMyObj = Object.keys(myObj).map(function(key) {
27+
return myObj[key];
28+
});
29+
});
30+
```
31+
That can be used as:
32+
```html
33+
<label>
34+
Order by:
35+
<select ng-model="orderProp" ng-options="prop for prop in ['id', 'name']"></select>
36+
</label>
37+
<div ng-repeat="item in arrFromMyObj | orderBy:orderProp">
38+
[{{ item.id }}] {{ item.name }}
39+
</div>
40+
```
41+
42+
You could as well convert the object to an array using a filter such as
43+
[toArrayFilter](https://github.com/petebacondarwin/angular-toArrayFilter):
44+
```html
45+
<label>
46+
Order by:
47+
<select ng-model="orderProp" ng-options="prop for prop in ['id', 'name']"></select>
48+
</label>
49+
<div ng-repeat="item in myObj | toArray:false | orderBy:orderProp">
50+
[{{ item.id }}] {{ item.name }}
51+
</div>
52+
```

src/ng/filter/orderBy.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
* Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
1010
* for strings and numerically for numbers. Note: if you notice numbers are not being sorted
1111
* as expected, make sure they are actually being saved as numbers and not strings.
12+
* Array-like values (e.g. NodeLists, jQuery objects, TypedArrays, Strings, etc) are also supported.
1213
*
13-
* @param {Array} array The array to sort.
14+
* @param {Array} array The array (or array-like object) to sort.
1415
* @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
1516
* used by the comparator to determine the order of elements.
1617
*
@@ -177,7 +178,10 @@ orderByFilter.$inject = ['$parse'];
177178
function orderByFilter($parse) {
178179
return function(array, sortPredicate, reverseOrder) {
179180

180-
if (!(isArrayLike(array))) return array;
181+
if (array == null) return array;
182+
if (!isArrayLike(array)) {
183+
throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
184+
}
181185

182186
if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
183187
if (sortPredicate.length === 0) { sortPredicate = ['+']; }

test/ng/filter/orderBySpec.js

+14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ describe('Filter: orderBy', function() {
88

99

1010
describe('(Arrays)', function() {
11+
it('should throw an exception if no array-like object is provided', function() {
12+
expect(function() { orderBy({}); }).
13+
toThrowMinErr('orderBy', 'notarray', 'Expected array but received: {}');
14+
});
15+
16+
it('should not throw an exception if a null or undefined value is provided', function() {
17+
expect(orderBy(null)).toEqual(null);
18+
expect(orderBy(undefined)).toEqual(undefined);
19+
});
20+
21+
it('should not throw an exception if an array-like object is provided', function() {
22+
expect(orderBy('cba')).toEqual(['a', 'b', 'c']);
23+
});
24+
1125
it('should return sorted array if predicate is not provided', function() {
1226
expect(orderBy([2, 1, 3])).toEqual([1, 2, 3]);
1327

0 commit comments

Comments
 (0)