Reputation: 288
I have an array of objects with user and interests. I would like to filter
the list based on interests. An user can have multiple interests and when selected interests check boxes the list should filter out based on those interests. I've used a basic filter on ng-repeat but it's not working.
If I select "sports" then "John" and "Rosaline" should be shown. If I select "movies" and "reading" then all 3 users should be shown. Below is my code.
Plunker: https://plnkr.co/edit/A0ojO3MH8rDhFJVXlEAs?p=preview
View:
<div ng-app="myApp" ng-controller="myController" style="padding:20px">
<input type="checkbox" ng-model="selection.reading" ng-true-value="'reading'" ng-false-value="''">reading
<input type="checkbox" ng-model="selection.sports" ng-true-value="'sports'" ng-false-value="''">sports
<input type="checkbox" ng-model="selection.movies" ng-true-value="'movies'" ng-false-value="''">movies
<br><br>
Selected Values: {{selectedValues}}
<hr>
<div ng-repeat="d in data | filter: selectedValues">
<h4>
Name: {{d.user}}
</h4>
<h4>
Interests: {{d.interests}}
</h4>
<hr>
</div>
Controller:
$scope.selection = {};
$scope.data = [
{
user: "John",
interests: ["reading","sports","movies"]
},
{
user: "David",
interests: ["movies","reading"]
},
{
user: "Rosaline",
interests: ["sports","movies"]
}
];
$scope.$watchCollection('selection', function () {
$scope.selectedValues = [];
angular.forEach($scope.selection, function (value, key) {
if (value) {
$scope.selectedValues.push(value);
}
});
});
Upvotes: 2
Views: 621
Reputation: 1059
Modify your html a bit in ng-repeat
<div ng-repeat="d in data" ng-hide="selectedValues.length > 0 && !filteredData(d.interests)">
<h4>
Name: {{d.user}}
</h4>
<h4>
Interests: {{d.interests}}
</h4>
<hr>
</div>
And add this function in script.js
$scope.filteredData = function (data) {
var found = false;
for (var i = 0; i < $scope.selectedValues.length; i++) {
if (data.indexOf($scope.selectedValues[i]) !== -1) { found = true; break; }
}
return found;
};
Live example : https://plnkr.co/edit/y8tqNiIU6p3x8d9zcdzL?p=preview
This will work ! Thanks
Upvotes: 1
Reputation: 6962
Here is one of many ways to filter objects in such examples.
I suggest getting rid of using $watch
in this situation and implement checkboxes functionality via simple ngChange
directive. Example below.
<input type="checkbox" ng-model="selection.reading" ng-change="selectInterest('reading')">reading
<input type="checkbox" ng-model="selection.sports" ng-change="selectInterest('sports')">sports
<input type="checkbox" ng-model="selection.movies" ng-change="selectInterest('movies')">movies
$scope.selectInterest = function(interest){
$scope.selection[interest] = !!$scope.selection[interest];
};
For filtering data I recommend using $filter or (just to simplify example) implement this filter like a controller function.
$scope.filterUsers = function(user){
return Object.keys($scope.selection).some(function (item) {
return user.interests.indexOf(item) >= 0 && $scope.selection[item];
});
};
You can look at and play with the whole code of my example at the link above.
Upvotes: 2
Reputation: 5762
Your can keep your filters in some array e.g. filterInterests
and then your HTML could looks like:
<div ng-repeat="d in data">
<div ng-show="hasInterest(d.interests, filterInterests)">
// Your code here
</div>
</div>
And your function will looks like:
function hasInterest(data, interests){
var result = false;
// Iterate over interests from filter and check them all in provided data
for(var=i, i<interests.length, i++){
if(data.indexOf(i) != -1) result = true
else result = false;
}
return result;
}
Upvotes: 0