AngularJS checkbox filter
Just to add onto @gkalpak answer, I found this codepen which allows you to provide the total amount left after an option is selected for each category.
Change the ng-repeat
from:
<div ng-repeat="wine in (ctrl.wines | filter:ctrl.filterByProperties) as filteredWines">
{{ wine.name }} <i>({{ wine.category }})</i>
</div>
To
<div ng-repeat="wine in filtered = (ctrl.wines | filter:ctrl.filterByProperties) as filteredWines">
{{ wine.name }} <i>({{ wine.category }})</i>
</div>
And with the input labels add:
<label>
<input type="checkbox" ng-model="ctrl.filter[prop][value]" />
{{ value }}({{(filtered | filter:value:true).length}})
</label>
There are several implementations possible. Here's one:
Have a
$scope.filter = {}
object to hold the state of each filter. E.g.{red: true, white: false...}
.Associate each checkbox with the corresponding property using
ng-model
. E.g.:input type="checkbox" ng-model="filter['red']" />
.Have a function (e.g.
$scope.filterByCategory(wine)
) that decides if a wine should be displayed or not (based on the$scope.filter
object).Use that function to filter the items based on their category. E.g.
<div ng-repeat="wine in wines | filter:filterByCategory">
The filterByCategory
function could be implemented like this:
function filterByCategory(wine) {
// Display the wine if
var displayWine =
// the wine's category checkbox is checked (`filter[category]` is true)
$scope.filter[wine.category] || // or
// no checkbox is checked (all `filter[...]` are false)
noFilter($scope.filter);
return displayWine;
};
where noFilter()
is a function that checks if there is any filter activated (and returns true
if there is none):
function noFilter(filterObj) {
return Object.
keys(filterObj).
every(function (key) { return !filterObj[key]; });
}
See, also, this short demo.
UPDATE:
I created a modified version, which supports multiple filters (not just filtering by category).
Basically, it dynamically detects the available properties (based on the first wine
element), adds controls (groups of check-boxes) for applying filters based on each property and features a custom filter function that:
- Filters each
wine
item, based on every property. - If a property has no filter applied (i.e. no check-box checked), it is ignored.
- If a property has check-boxes checked, it is used for filtering out
wine
items (see above). - There is code for applying multiple filters using AND (i.e. all properties must match) or OR (at least one property must match).
See, also, this updated demo.
I prefer use filter
as $filter
app.filter('someFilter',checkboxFilter)
checkboxFilter() {
return function (arr,filter,key,noOne=false) {
// arr is an array of objects
// filter is checkbox filter. someting like {1:true,2:false}
// key is a property in ech object inside arr
// noOne is a behavior if none of checkbox is activated (default:false)
if (!arr.length) return null;
function noOneCheck(filter) {
return Object.keys(filter).every((key) => {
return !filter[key]
})
}
return arr.filter((i) => {
return filter[i[key]] || (noOne && noOneCheck(filter))
})
}
};
html:
ng-repeat="u in project.projectTeamInvite | checkbox:project.status:'status' track by $index">