I have a giant list of entries with thousands of elements, i have created a list of checkbox filters for each column thats a unique list of each value in that column. I now want to filter the list based on what the checkboxes the user clicks in the app. The list looks something like this
[{
Value1: "val",
Value2: "more value",
Value3: "1"
},{
Value1: "val1",
Value2: "test",
Value3: "1"
},{
Value1: "val1",
Value2: "test",
Value3: "2"
},{
Value1: "val",
Value2: "test",
Value3: "3"
}];
So the filters woul look something like this.
Value1
- val
- val1
value2
- test
value 3
- 1
- 2
- 3
if a user checks 3 in the value 3 boxes i just wanna show the objects with value3 = 3, if they check 2 in the value 3 boxes i wanna show value 3 = 3 OR value 3 = 2. if they check val1 in value 1 boxes i wanna show objects where Value 3 = 3 OR 2 AND value 1 = val1. meaning i would only show the 3rd element in the array because it meets all 3 conditions.
How can i achieve this using Typescript/Javascript. All filterable values are strings
currently im trying something like this, but that just shows everything that has one value matching.
let newFilterObj = [{ fieldName: "value3", value: "3" }, { fieldName: "value3", value: "2" }, { fieldName: "value1", value: "val1" }]
let newList = ListAllItems.filter((i) => {
const found = newFilterObj.some(element => {
return i[element.fieldName] === element.value;
});
return found;
});
CodePudding user response:
you can do something like this
basically you group all your filters by key
than you use every
for the AND condition
and include
fro the OR condition
const applyFilters = (data, filter) => {
const groupFilter = Object.values(filter.reduce((res, {fieldName, value}) => {
const existingFilter = res[fieldName] || {fieldName, values:[]}
return {
...res,
[fieldName]: {
...existingFilter,
values: [...existingFilter.values, value]
}
}
}, {}))
return data.filter(d => groupFilter.every(f => f.values.includes(d[f.fieldName])))
}
const ListAllItems = [{
Value1: "val",
Value2: "more value",
Value3: "1"
},{
Value1: "val1",
Value2: "test",
Value3: "1"
},{
Value1: "val1",
Value2: "test",
Value3: "2"
},{
Value1: "val",
Value2: "test",
Value3: "3"
}];
let newFilterObj = [{ fieldName: "Value3", value: "3" }, { fieldName: "Value3", value: "2" }, { fieldName: "Value1", value: "val1" }]
console.log(applyFilters(ListAllItems, newFilterObj))
CodePudding user response:
You should collect all available filter values and than check
const ListAllItems = [{
value1: 'val',
value2: 'more value',
value3: '1',
}, {
value1: 'val1',
value2: 'test',
value3: '1',
}, {
value1: 'val1',
value2: 'test',
value3: '2',
}, {
value1: 'val',
value2: 'test',
value3: '3',
},
]
let newFilterObj = [{ fieldName: 'value3', value: '3' }, { fieldName: 'value3', value: '2' }, {
fieldName: 'value1',
value: 'val1',
},
]
const filedValues = {}
newFilterObj.forEach(({ fieldName, value }) => {
if (filedValues[fieldName]) {
filedValues[fieldName].push(value)
} else {
filedValues[fieldName] = [value]
}
})
console.log(filedValues)
/*
{
"value3": [
"3",
"2"
],
"value1": [
"val1"
]
}
*/
let newList = ListAllItems.filter((i) => {
for ([key, value] of Object.entries(filedValues)) {
if (!value.includes(i[key])) {
return false
}
}
return true
})
console.log('newList', newList)
/*
[
{
"value1": "val1",
"value2": "test",
"value3": "2"
}
]
*/