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">
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>
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 */
83107function 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 }
0 commit comments