I have an array of objects with some bool and int properties:
let employees = [
{ isSkilled: false, isLeader: false, departmentHeadType: 0 },
{ isSkilled: true, isLeader: false, departmentHeadType: 1 },
{ isSkilled: true, isLeader: true, departmentHeadType: 2 }
]
And there is a select where user can check options (in any combinations) by which employees will be filtered:
So after selection I have a filter something like that:
//if user selected "Skilled", "Leaders" and "Heads of departments"
var filter1 = { isSkilled: true, isLeader: true, departmentHeadType: 2 };
//if user selected "Skilled", "Newbie" (so I simply omit isSkilled property in filter
//as both variants are ok), "Leaders", "Heads of departments" and "Deputy heads of departments"
var filter2 = { isLeader: true, departmentHeadType: [1, 2] };
For filter1
I can use the following code:
const filtered = employees.filter(object => JSON.stringify(filter1) == JSON.stringify(object));
But JSON.stringify
works only if compared objects have the same properties in the same order. And it will not work for filter2
where isSkilled
is omitted and departmentHeadType
is array. For filter2
the only idea I have is several ifs and specific properties filtering in each case (that approach is ugly and and not scalable as employee properties grow and thus filter options increase).
Is there a better and more generic aproach for this?
As you noted, JSON.stringify()
is not a great option because you cannot reliably guarantee object property order.
You could make it dynamic by iterating the filter object entries (key / value pairs) and creating predicate functions for each, comparing the filter value against the object value for the same key.
You'd need a little extra logic to detect arrays and use an includes check.
const filterRecords = (array, filter) => {
const predicates = Object.entries(filter).map(
([key, val]) =>
(obj) =>
Array.isArray(val) ? val.includes(obj[key]) : val === obj[key],
);
return array.filter((e) => predicates.every((p) => p(e)));
};
let employees = [
{ isSkilled: false, isLeader: false, departmentHeadType: 0 },
{ isSkilled: true, isLeader: false, departmentHeadType: 1 },
{ isSkilled: true, isLeader: true, departmentHeadType: 2 }
];
//if user selected "Skilled", "Leaders" and "Heads of departments"
var filter1 = { isSkilled: true, isLeader: true, departmentHeadType: 2 };
//if user selected "Skilled", "Newbie" (so I simply omit isSkilled property in filter
//as both variants are ok), "Leaders", "Heads of departments" and "Deputy heads of departments"
var filter2 = { isLeader: true, departmentHeadType: [1, 2] };
console.log('filter1', filterRecords(employees, filter1));
console.log('filter2', filterRecords(employees, filter2));
.as-console-wrapper { max-height: 100% !important; }