Reputation: 325
I have an array of users and also an array of filters.
I need to filter users based on the array of filters but when I do it will filter on one array but not the others
My filters object looks like this:
filters: {
levels: [],
locations: ['Laois'],
subjects: ['Art']
}
My users look like this:
const users = [
{
email: '[email protected]',
levels: ['Ordinary'],
location: 'Laois',
subjects: ['Art', 'German']
},
{
email: '[email protected]',
levels: ['Higher', 'Ordinary'],
location: 'Laois',
subjects: ['English', 'German']
}
]
Based on the filter above, once filtered the users should only be one because it contains 'Art' and 'Laois':
[{
email: '[email protected]',
levels: ['Ordinary'],
location: 'Laois',
subjects: ['Art', 'German']
},
]
But I am still getting the two users:
EDIT My Code:
applyFilter = (visable) => {
let { filters, users } = this.state;
const { subjects, locations, levels } = filters;
let filteredUsers = [];
const filteredData = users.filter((user) =>
user.subjects.some(subject => subjects.includes(subject)) ||
locations.some(location => location === user.location) ||
user.levels.some(level => levels.includes(level))
);
console.log(filteredData)
if (!subjects.length && !locations.length && !levels.length) {
filteredUsers = users;
} else {
filteredUsers = filteredData;
}
this.setState({
filterModalVisible: visable,
filteredResults: filteredUsers.length >= 0 ? filteredUsers : [],
});
}
Upvotes: 2
Views: 1861
Reputation: 28445
You can have a generic solution for any filter key by using Array.filter, Array.some and Array.includes
filter
to validate each entry against all the filter conditionsfilter key
is different from the key in object
, add a specific check for that where we check for location to be included in the locations arraylet filters = {levels: [],locations: ['Laois'],subjects: ['Art']};
let users = [{email: '[email protected]',levels: ['Ordinary'],location: 'Laois',subjects: ['Art', 'German']},{email: '[email protected]',levels: ['Higher', 'Ordinary'],location: 'Laois',subjects: ['English', 'German']}];
users = users.filter(v => {
let response = true;
for (let filter in filters) {
if(!filters[filter].length) continue;
if(filter === "locations") {
response = response && filters.locations.includes(v.location)
} else response = response && v[filter].some(f => filters[filter].includes(f));
if(!response) break;
}
return response;
});
console.log(users);
Upvotes: 1
Reputation: 2323
&&
instead of ||
if you want to match all conditionsapplyFilter = (visable) => {
let { filters, users } = this.state;
const { subjects, locations, levels } = filters;
const filteredResults = users.filter((user) =>
(!subjects.length || user.subjects.some(subject => subjects.includes(subject))) &&
(!locations.length || locations.some(location => location === user.location)) &&
(!levels.length || user.levels.some(level => levels.includes(level)))
);
this.setState({
filterModalVisible: visable,
filteredResults
});
}
Upvotes: 0
Reputation: 12152
Using filter inside filter
const filters = {
levels: [],
locations: ['Laois'],
subjects: ['Art']
}
const users = [
{
email: '[email protected]',
levels: ['Ordinary'],
location: 'Laois',
subjects: ['Art', 'German']
},
{
email: '[email protected]',
levels: ['Higher', 'Ordinary'],
location: 'Laois',
subjects: ['English', 'German']
}
]
console.log(users.filter((e) => {
var arr = e.subjects.filter((x) => filters.subjects.includes(x))
if (arr.length > 0 && filters.locations.includes(e.location))
return e
}))
Upvotes: 0
Reputation: 68933
You can try with filter()
const filters = {
levels: [],
locations: ['Laois'],
subjects: ['Art']
}
const users = [
{
email: '[email protected]',
levels: ['Ordinary'],
location: 'Laois',
subjects: ['Art', 'German']
},
{
email: '[email protected]',
levels: ['Higher', 'Ordinary'],
location: 'Laois',
subjects: ['English', 'German']
}
]
var res = users.filter(info => info.location==filters.locations[0] && info.subjects.includes(filters.subjects[0]));
console.log(res);
Upvotes: 1
Reputation: 122027
You can do this using filter
and every
methods by checking if every element from the filters value exist in the user value with the same key.
const filters = {"levels":[],"locations":["Laois"],"subjects":["Art"]}
const users = [{"email":"[email protected]","levels":["Ordinary"],"locations":"Laois","subjects":["Art","German"]},{"email":"[email protected]","levels":["Higher","Ordinary"],"locations":"Laois","subjects":["English","German"]}]
const res = users.filter(user => {
return Object.entries(filters)
.every(([key, value]) => {
if (Array.isArray(value)) {
return value.every(filter => {
return user[key] && user[key].includes(filter)
})
} else {
return user[key] == value
}
})
})
console.log(res)
Upvotes: 1