Reputation: 43
I have the following data:
const products = [{
name: "Product 1",
options: [
{
id: 1,
optionName: "Color",
value: "Red"
},
{
id: 2,
optionName: "Size",
value: "Small"
}
]},
{
name: "Product 2",
options: [
{
id: 1,
optionName: "Color",
value: "Red"
},
{
id: 2,
optionName: "Size",
value: "Large"
}
]}];
And I have a filter object, that is created dynamically:
let selectedFilters = {"Color":"Red", "Size":"Small"};
I want to get only the products that meet all the criteria specified in the selectedFilters object. In the example, I should only get "Product 1"
This is what I have tried so far but none of these work as I need:
let filteredProducts = [];
let keys = Object.keys(selectedFilters);
keys.forEach(function(filterKey) {
let f = _.filter(products, function(o) {
let flag = false;
let searchFilterKey = selectedFilters[filterKey];
let index = o.options.findIndex(o=> o.optionName == filterKey && o.value == searchFilterKey);
if (index > 0)
return o;
});
filteredProducts = f;
});
products.filter(p =>
Object.keys(selectedFilters).every(k =>
{
return p.options.filter(o => o.optionName == k && o.value == selectedFilters[k]);
}));
Upvotes: 4
Views: 1128
Reputation: 116
You can try to use Array.filter, and then use Array.every function foreach product.options
to check if it's properties exist in the selectedFilters object.
const products = [{
name: "Product 1",
options: [
{
id: 1,
optionName: "Color",
value: "Red"
},
{
id: 2,
optionName: "Size",
value: "Small"
}
]
},
{
name: "Product 2",
options: [
{
id: 1,
optionName: "Color",
value: "Red"
},
{
id: 2,
optionName: "Size",
value: "Large"
}
]
}
];
let selectedFilters = {"Color":"Red", "Size":"Small"};
let filteredProducts = products.filter(product => {
return product.options.every(({ optionName, value }) => !!selectedFilters[optionName] && selectedFilters[optionName] === value);
});
console.log(filteredProducts);
Upvotes: 0
Reputation: 4616
You can get the result with Array#filter, Array#every and Array#some. The filter-array can be dynamical extended and it's not necessary that it is sorted or that all of filter-properties be present.
I filter over the product-array. Here had for every product, which will be selected, all filters of the filter-array to be fullfilled. For every filter-criterium I look if this criteria is for some options for this product ok. For this had the optionname and the value to match.
function myFilter(array, filters) {
return array.filter(({options}) =>
Object.entries(filters).every(([key, value]) =>
options.some((option) =>
option.optionName===key && option.value===value
)
)
);
}
const products = [{
name: "Product 1",
options: [
{
id: 1,
optionName: "Color",
value: "Red"
},
{
id: 2,
optionName: "Size",
value: "Small"
}
]},
{
name: "Product 2",
options: [
{
id: 1,
optionName: "Color",
value: "Red"
},
{
id: 2,
optionName: "Size",
value: "Large"
}
]}];
let filters= {"Color":"Red", "Size":"Small"};
console.log(myFilter(products, filters));
Upvotes: 0
Reputation: 13703
You could get the values of the filter in an array and run an every function with a matching condition. Since the 'value' is the significant property here use it to run its value against the selectedFilters.
Do the same for the keys if you they are part of the criteria
const products = [{
name: "Product 1",
options: [{
id: 1,
optionName: "Color",
value: "Red"
},
{
id: 2,
optionName: "Size",
value: "Small"
}
]
},
{
name: "Product 2",
options: [{
id: 1,
optionName: "Color",
value: "Red"
},
{
id: 2,
optionName: "Size",
value: "Large"
}
]
}
]
let selectedFilters = {
"Color": "Red",
"Size": "Small"
};
const arrFilterValues = Object.values(selectedFilters);
const arrFilterKeys = Object.keys(selectedFilters);
const result = products.filter(x => {
return x.options.every(y=> arrFilterValues.includes(y['value']) && arrFilterKeys.includes(y['optionName']))
})
console.log(result)
Upvotes: 1
Reputation: 89294
You can filter based on the entries of the object.
const products = [{
name: "Product 1",
options: [
{
id: 1,
optionName: "Color",
value: "Red"
},
{
id: 2,
optionName: "Size",
value: "Small"
}
]},
{
name: "Product 2",
options: [
{
id: 1,
optionName: "Color",
value: "Red"
},
{
id: 2,
optionName: "Size",
value: "Large"
}
]}];
let selectedFilters = {"Color":"Red", "Size":"Small"};
let entries = Object.entries(selectedFilters);
const res = products.filter(({options})=>
entries.every(([k,v])=>options.some(o=>o.optionName===k && o.value === v)));
console.log(res);
Upvotes: 1