diff options
| author | Rosina Bignall | 2013-01-23 18:18:18 -0600 |
|---|---|---|
| committer | Misko Hevery | 2013-02-14 14:43:55 -0800 |
| commit | ace54ff08c4593195b49eadb04d258e6409d969e (patch) | |
| tree | 60fdeef31aba4aed772821bc029b7a623830b272 | |
| parent | f5835963d5982003a713dd354eefd376ed39ac02 (diff) | |
| download | angular.js-ace54ff08c4593195b49eadb04d258e6409d969e.tar.bz2 | |
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.
| -rw-r--r-- | src/ng/filter/filter.js | 80 | ||||
| -rw-r--r-- | test/ng/filter/filterSpec.js | 53 |
2 files changed, 116 insertions, 17 deletions
diff --git a/src/ng/filter/filter.js b/src/ng/filter/filter.js index 467f6699..c2a06686 100644 --- a/src/ng/filter/filter.js +++ b/src/ng/filter/filter.js @@ -32,6 +32,22 @@ * called for each element of `array`. The final result is an array of those elements that * the predicate returned true for. * + * @param {function(expected, actual)|true|undefined} comparator Comparator which is used in + * determining if the expected value (from the filter expression) and actual value (from + * the object in the array) should be considered a match. + * + * Can be one of: + * + * - `function(expected, actual)`: + * The function will be given the object value and the predicate value to compare and + * should return true if the item should be included in filtered result. + * + * - `true`: A shorthand for `function(expected, actual) { return angular.equals(expected, actual)}`. + * this is essentially strict comparison of expected and actual. + * + * - `false|undefined`: A short hand for a function which will look for a substring match in case + * insensitive way. + * * @example <doc:example> <doc:source> @@ -39,7 +55,8 @@ {name:'Mary', phone:'800-BIG-MARY'}, {name:'Mike', phone:'555-4321'}, {name:'Adam', phone:'555-5678'}, - {name:'Julie', phone:'555-8765'}]"></div> + {name:'Julie', phone:'555-8765'}, + {name:'Juliette', phone:'555-5678'}]"></div> Search: <input ng-model="searchText"> <table id="searchTextResults"> @@ -53,9 +70,10 @@ Any: <input ng-model="search.$"> <br> Name only <input ng-model="search.name"><br> Phone only <input ng-model="search.phone"å><br> + Equality <input type="checkbox" ng-model="strict"><br> <table id="searchObjResults"> <tr><th>Name</th><th>Phone</th><tr> - <tr ng-repeat="friend in friends | filter:search"> + <tr ng-repeat="friend in friends | filter:search:strict"> <td>{{friend.name}}</td> <td>{{friend.phone}}</td> <tr> @@ -75,13 +93,19 @@ it('should search in specific fields when filtering with a predicate object', function() { input('search.$').enter('i'); expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')). - toEqual(['Mary', 'Mike', 'Julie']); + toEqual(['Mary', 'Mike', 'Julie', 'Juliette']); + }); + it('should use a equal comparison when comparator is true', function() { + input('search.name').enter('Julie'); + input('strict').check(); + expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')). + toEqual(['Julie']); }); </doc:scenario> </doc:example> */ function filterFilter() { - return function(array, expression) { + return function(array, expression, comperator) { if (!(array instanceof Array)) return array; var predicates = []; predicates.check = function(value) { @@ -92,20 +116,43 @@ function filterFilter() { } return true; }; + switch(typeof comperator) { + case "function": + break; + case "boolean": + if(comperator == true) { + comperator = function(obj, text) { + return angular.equals(obj, text); + } + break; + } + default: + comperator = function(obj, text) { + text = (''+text).toLowerCase(); + return (''+obj).toLowerCase().indexOf(text) > -1 + }; + } var search = function(obj, text){ - if (text.charAt(0) === '!') { + if (typeof text == 'string' && text.charAt(0) === '!') { return !search(obj, text.substr(1)); } switch (typeof obj) { case "boolean": case "number": case "string": - return ('' + obj).toLowerCase().indexOf(text) > -1; + return comperator(obj, text); case "object": - for ( var objKey in obj) { - if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) { - return true; - } + switch (typeof text) { + case "object": + return comperator(obj, text); + break; + default: + for ( var objKey in obj) { + if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) { + return true; + } + } + break; } return false; case "array": @@ -118,7 +165,7 @@ function filterFilter() { default: return false; } - }; + }; switch (typeof expression) { case "boolean": case "number": @@ -128,19 +175,18 @@ function filterFilter() { for (var key in expression) { if (key == '$') { (function() { - var text = (''+expression[key]).toLowerCase(); - if (!text) return; + if (!expression[key]) return; + var path = key predicates.push(function(value) { - return search(value, text); + return search(value, expression[path]); }); })(); } else { (function() { + if (!expression[key]) return; var path = key; - var text = (''+expression[key]).toLowerCase(); - if (!text) return; predicates.push(function(value) { - return search(getter(value, path), text); + return search(getter(value,path), expression[path]); }); })(); } diff --git a/test/ng/filter/filterSpec.js b/test/ng/filter/filterSpec.js index a33358d0..4f357371 100644 --- a/test/ng/filter/filterSpec.js +++ b/test/ng/filter/filterSpec.js @@ -66,4 +66,57 @@ describe('Filter: filter', function() { expect(filter(items, '!isk').length).toBe(1); expect(filter(items, '!isk')[0]).toEqual(items[1]); }); + + describe('should support comparator', function() { + + it('as equality when true', function() { + var items = ['misko', 'adam', 'adamson']; + var expr = 'adam'; + expect(filter(items, expr, true)).toEqual([items[1]]); + expect(filter(items, expr, false)).toEqual([items[1], items[2]]); + + var items = [ + {key: 'value1', nonkey: 1}, + {key: 'value2', nonkey: 2}, + {key: 'value12', nonkey: 3}, + {key: 'value1', nonkey:4}, + {key: 'Value1', nonkey:5} + ]; + var expr = {key: 'value1'}; + expect(filter(items, expr, true)).toEqual([items[0], items[3]]); + + var items = [ + {key: 1, nonkey: 1}, + {key: 2, nonkey: 2}, + {key: 12, nonkey: 3}, + {key: 1, nonkey:4} + ]; + var expr = { key: 1 }; + expect(filter(items, expr, true)).toEqual([items[0], items[3]]); + + var expr = 12; + expect(filter(items, expr, true)).toEqual([items[2]]); + }); + + it('and use the function given to compare values', function() { + var items = [ + {key: 1, nonkey: 1}, + {key: 2, nonkey: 2}, + {key: 12, nonkey: 3}, + {key: 1, nonkey:14} + ]; + var expr = {key: 10}; + var comparator = function (obj,value) { + return obj > value; + } + expect(filter(items, expr, comparator)).toEqual([items[2]]); + + expr = 10; + expect(filter(items, expr, comparator)).toEqual([items[2], items[3]]); + + }); + + + }); + }); |
