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

Commit ace54ff

Browse files
bignallmhevery
authored andcommitted
feat(filter): Add comparison function to filter
Add optional comparator function argument to $filter('filter')(array, expression, comparator) such that the comparator function is used to compare the values and predicates. When true, defaults to equality. When missing defaults to substring matching.
1 parent f583596 commit ace54ff

File tree

2 files changed

+116
-17
lines changed

2 files changed

+116
-17
lines changed

src/ng/filter/filter.js

+63-17
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,31 @@
3232
* called for each element of `array`. The final result is an array of those elements that
3333
* the predicate returned true for.
3434
*
35+
* @param {function(expected, actual)|true|undefined} comparator Comparator which is used in
36+
* determining if the expected value (from the filter expression) and actual value (from
37+
* the object in the array) should be considered a match.
38+
*
39+
* Can be one of:
40+
*
41+
* - `function(expected, actual)`:
42+
* The function will be given the object value and the predicate value to compare and
43+
* should return true if the item should be included in filtered result.
44+
*
45+
* - `true`: A shorthand for `function(expected, actual) { return angular.equals(expected, actual)}`.
46+
* this is essentially strict comparison of expected and actual.
47+
*
48+
* - `false|undefined`: A short hand for a function which will look for a substring match in case
49+
* insensitive way.
50+
*
3551
* @example
3652
<doc:example>
3753
<doc:source>
3854
<div ng-init="friends = [{name:'John', phone:'555-1276'},
3955
{name:'Mary', phone:'800-BIG-MARY'},
4056
{name:'Mike', phone:'555-4321'},
4157
{name:'Adam', phone:'555-5678'},
42-
{name:'Julie', phone:'555-8765'}]"></div>
58+
{name:'Julie', phone:'555-8765'},
59+
{name:'Juliette', phone:'555-5678'}]"></div>
4360
4461
Search: <input ng-model="searchText">
4562
<table id="searchTextResults">
@@ -53,9 +70,10 @@
5370
Any: <input ng-model="search.$"> <br>
5471
Name only <input ng-model="search.name"><br>
5572
Phone only <input ng-model="search.phone"å><br>
73+
Equality <input type="checkbox" ng-model="strict"><br>
5674
<table id="searchObjResults">
5775
<tr><th>Name</th><th>Phone</th><tr>
58-
<tr ng-repeat="friend in friends | filter:search">
76+
<tr ng-repeat="friend in friends | filter:search:strict">
5977
<td>{{friend.name}}</td>
6078
<td>{{friend.phone}}</td>
6179
<tr>
@@ -75,13 +93,19 @@
7593
it('should search in specific fields when filtering with a predicate object', function() {
7694
input('search.$').enter('i');
7795
expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
78-
toEqual(['Mary', 'Mike', 'Julie']);
96+
toEqual(['Mary', 'Mike', 'Julie', 'Juliette']);
97+
});
98+
it('should use a equal comparison when comparator is true', function() {
99+
input('search.name').enter('Julie');
100+
input('strict').check();
101+
expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
102+
toEqual(['Julie']);
79103
});
80104
</doc:scenario>
81105
</doc:example>
82106
*/
83107
function filterFilter() {
84-
return function(array, expression) {
108+
return function(array, expression, comperator) {
85109
if (!(array instanceof Array)) return array;
86110
var predicates = [];
87111
predicates.check = function(value) {
@@ -92,20 +116,43 @@ function filterFilter() {
92116
}
93117
return true;
94118
};
119+
switch(typeof comperator) {
120+
case "function":
121+
break;
122+
case "boolean":
123+
if(comperator == true) {
124+
comperator = function(obj, text) {
125+
return angular.equals(obj, text);
126+
}
127+
break;
128+
}
129+
default:
130+
comperator = function(obj, text) {
131+
text = (''+text).toLowerCase();
132+
return (''+obj).toLowerCase().indexOf(text) > -1
133+
};
134+
}
95135
var search = function(obj, text){
96-
if (text.charAt(0) === '!') {
136+
if (typeof text == 'string' && text.charAt(0) === '!') {
97137
return !search(obj, text.substr(1));
98138
}
99139
switch (typeof obj) {
100140
case "boolean":
101141
case "number":
102142
case "string":
103-
return ('' + obj).toLowerCase().indexOf(text) > -1;
143+
return comperator(obj, text);
104144
case "object":
105-
for ( var objKey in obj) {
106-
if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
107-
return true;
108-
}
145+
switch (typeof text) {
146+
case "object":
147+
return comperator(obj, text);
148+
break;
149+
default:
150+
for ( var objKey in obj) {
151+
if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
152+
return true;
153+
}
154+
}
155+
break;
109156
}
110157
return false;
111158
case "array":
@@ -118,7 +165,7 @@ function filterFilter() {
118165
default:
119166
return false;
120167
}
121-
};
168+
};
122169
switch (typeof expression) {
123170
case "boolean":
124171
case "number":
@@ -128,19 +175,18 @@ function filterFilter() {
128175
for (var key in expression) {
129176
if (key == '$') {
130177
(function() {
131-
var text = (''+expression[key]).toLowerCase();
132-
if (!text) return;
178+
if (!expression[key]) return;
179+
var path = key
133180
predicates.push(function(value) {
134-
return search(value, text);
181+
return search(value, expression[path]);
135182
});
136183
})();
137184
} else {
138185
(function() {
186+
if (!expression[key]) return;
139187
var path = key;
140-
var text = (''+expression[key]).toLowerCase();
141-
if (!text) return;
142188
predicates.push(function(value) {
143-
return search(getter(value, path), text);
189+
return search(getter(value,path), expression[path]);
144190
});
145191
})();
146192
}

test/ng/filter/filterSpec.js

+53
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,57 @@ describe('Filter: filter', function() {
6666
expect(filter(items, '!isk').length).toBe(1);
6767
expect(filter(items, '!isk')[0]).toEqual(items[1]);
6868
});
69+
70+
describe('should support comparator', function() {
71+
72+
it('as equality when true', function() {
73+
var items = ['misko', 'adam', 'adamson'];
74+
var expr = 'adam';
75+
expect(filter(items, expr, true)).toEqual([items[1]]);
76+
expect(filter(items, expr, false)).toEqual([items[1], items[2]]);
77+
78+
var items = [
79+
{key: 'value1', nonkey: 1},
80+
{key: 'value2', nonkey: 2},
81+
{key: 'value12', nonkey: 3},
82+
{key: 'value1', nonkey:4},
83+
{key: 'Value1', nonkey:5}
84+
];
85+
var expr = {key: 'value1'};
86+
expect(filter(items, expr, true)).toEqual([items[0], items[3]]);
87+
88+
var items = [
89+
{key: 1, nonkey: 1},
90+
{key: 2, nonkey: 2},
91+
{key: 12, nonkey: 3},
92+
{key: 1, nonkey:4}
93+
];
94+
var expr = { key: 1 };
95+
expect(filter(items, expr, true)).toEqual([items[0], items[3]]);
96+
97+
var expr = 12;
98+
expect(filter(items, expr, true)).toEqual([items[2]]);
99+
});
100+
101+
it('and use the function given to compare values', function() {
102+
var items = [
103+
{key: 1, nonkey: 1},
104+
{key: 2, nonkey: 2},
105+
{key: 12, nonkey: 3},
106+
{key: 1, nonkey:14}
107+
];
108+
var expr = {key: 10};
109+
var comparator = function (obj,value) {
110+
return obj > value;
111+
}
112+
expect(filter(items, expr, comparator)).toEqual([items[2]]);
113+
114+
expr = 10;
115+
expect(filter(items, expr, comparator)).toEqual([items[2], items[3]]);
116+
117+
});
118+
119+
120+
});
121+
69122
});

0 commit comments

Comments
 (0)