Reputation: 3707
Using Angular v1.5 I've got a simple one property filter working but I would like to filter on two properties. Searching came up with some custom filters but that seemed like a bunch of code to just look at an extra property.
In my below example I would like the filter to work on both FirstName and LastName.
Filter Name: <input type="text" ng-model="memberFilter.FirstName" />
<p />
<div class="table-responsive">
<table class="table table-bordered table-striped table-hover">
<tr class="info">
<th ng-click="doSort('FirstName')">First Name</th>
<th ng-click="doSort('LastName')">Last Name</th>
<th ng-click="doSort('EmailPrimary')">Email</th>
<th ng-click="doSort('PhonePrimary')">Phone</th>
<th> </th>
</tr>
<tr ng-repeat="member in members | filter:memberFilter | orderBy:sortBy:reverse">
<td>{{ member.FirstName }}</td>
<td>{{ member.LastName }}</td>
<td><a href="mailto:{{ member.EmailPrimary }}">{{ member.EmailPrimary }}</a></td>
<td class="text-center">{{ member.PhonePrimary | tel }}</td>
<td class="text-center"><a href="#/memberDetail/{{ member.MemberId }}">View</a></td>
</tr>
</table>
</div>
I tried adding an array to the ng-model but that didn't work:
ng-model="[memberFilter.FirstName,memberFilter.LastName]"
Updated Question
I'm new with Angular in general and just wrote my first custom filter the other day to display formatted telephone numbers. You can see my filter in the original code but I changed the name from "tel" to "phone". It's one I found on SO and I was able to get it to work. So I assumed I could just add the search filter to this file and not create a new js file for each filter. However, when I added it my Angular stopped working. I thought I added it correct but I might have a semi-colon in the wrong spot or maybe it's not possible. I still haven't figured out a good way to debug in Angular.
Here is a file I created for my filters called filter.js.
angular.module('appFilters', [])
.filter('phone', function () {
return function (phone) {
if (!phone) { return ''; }
var value = phone.toString().trim().replace(/^\+/, '');
if (value.match(/[^0-9]/)) {
return phone;
}
var country, city, number;
switch (value.length) {
case 10: // +1PPP####### -> C (PPP) ###-####
country = 1;
city = value.slice(0, 3);
number = value.slice(3);
break;
case 11: // +CPPP####### -> CCC (PP) ###-####
country = value[0];
city = value.slice(1, 4);
number = value.slice(4);
break;
case 12: // +CCCPP####### -> CCC (PP) ###-####
country = value.slice(0, 3);
city = value.slice(3, 5);
number = value.slice(5);
break;
default:
return phone;
}
if (country == 1) {
country = "";
}
number = number.slice(0, 3) + '-' + number.slice(3);
return (country + " (" + city + ") " + number).trim();
};
})
.filter('customMemberFilter', function () {
return function (memberList, query) {
// make sure a query value was passed
if (query) {
query = query.toLowerCase();
var out = [];
angular.forEach(memberList, function (member) {
if ((member.FirstName.toLowerCase().includes(query)) ||
(member.LastName.toLowerCase().includes(query))) {
out.push(member);
}
});
return out;
} else {
return memberList;
}
}
});
and this is my app.js where the appFilters are added
(function () {
var app = angular.module('troopApp', ['ngRoute','appFilters']); //('moduleName', [array of injected modules])
app.config(function($routeProvider) {
$routeProvider
.when('/', {
controller: 'MembersController',
templateUrl: 'app/views/members.html'
})
.when('/memberDetail/:memberId', {
controller: 'MemberDetailController',
templateUrl: 'app/views/memberDetail.html'
})
.otherwise({ redirectTo: '/'});
});
}());
This is what I changed my HTML code to:
Filter Name: <input type="text" ng-model="memberFilter" />
and
<tr ng-repeat="member in members | customMemberFilter:memberFilter | orderBy:sortBy:reverse">
Upvotes: 1
Views: 83
Reputation: 7194
The solution is very simple.
Change this line:
Filter Name: <input type="text" ng-model="memberFilter.FirstName" />
to this:
Filter Name: <input type="text" ng-model="memberFilter" />
By default Angular will do deep property filtering. Since you were creating an object with a FirstName
property to use as your filter you were effectively limiting the filter to that property on your target object(s). By making the filter more generic Angular will attempt to match on any property of the target object(s).
Update: This will, of course, match on all properties of your member object which may be undesirable. If this is the case then, as you suspected, you'll have to write a custom filter. Here's one way you could write it:
.filter('customMemberFilter', function() {
return function(memberList, query) {
// make sure a query value was passed
if (query) {
query = query.toLowerCase();
var out = [];
angular.forEach(memberList, function(member) {
if ((member.FirstName.toLowerCase().includes(query)) ||
(member.LastName.toLowerCase().includes(query))) {
out.push(member);
}
});
return out;
} else {
return memberList;
}
}
})
And then you would use it:
<tr ng-repeat="member in members | customMemberFilter:memberFilter | orderBy:sortBy:reverse">
Upvotes: 1