Reputation:
This is my array from a webservices.
array = [{category: "Amphibian", common_name: "African Clawed Frog"},{category: "Mammal", common_name: "African Pygmy Hedgehog"},{common_name: "African Spurred Tortoise"}];
now when I call this function like this:
function filterByKey(array, "common_name", "African", "includes") //it works..
so now when I want to filter by category, like this:
function filterByKey(array, "category", "Mammal", "includes") // it doesn't work
but because the third row doesn't have a category column, it fails stating the following error:
Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
this is my function
function filterByKey(array, key, value, matchOrContain) {
if (matchOrContain == "match") {
var result = array.filter(o => Object.keys(o).some(k => o[key].toLowerCase() === value.toLowerCase()));
} else if (matchOrContain == "includes") {
var result = array.filter(o => Object.keys(o).some(k => o[key].toLowerCase().includes(value
.toLowerCase())));
}
return result;
}
How can I avoid getting that error but in the same times filter out the array? Any help will be much appreciated. Thanks!!
Upvotes: 2
Views: 100
Reputation: 371193
Easiest tweak would be to use optional chaining, to only call toLowerCase
if the key exists:
const array = [{
category: "Amphibian",
common_name: "African Clawed Frog"
}, {
category: "Mammal",
common_name: "African Pygmy Hedgehog"
}, {
common_name: "African Spurred Tortoise"
}];
console.log(filterByKey(array, "category", "Mammal", "includes"))
function filterByKey(array, key, value, matchOrContain) {
if (matchOrContain == "match") {
var result = array.filter(o => Object.keys(o).some(k => o[key]?.toLowerCase() === value.toLowerCase()));
} else if (matchOrContain == "includes") {
var result = array.filter(o => Object.keys(o).some(k => o[key]?.toLowerCase().includes(value
.toLowerCase())));
}
return result;
}
You could significantly DRY the code by declaring the callback up front, too:
const array = [{
category: "Amphibian",
common_name: "African Clawed Frog"
}, {
category: "Mammal",
common_name: "African Pygmy Hedgehog"
}, {
common_name: "African Spurred Tortoise"
}];
console.log(filterByKey(array, "category", "Mammal", "includes"))
function filterByKey(array, key, value, matchOrContain) {
const lowerValue = value.toLowerCase();
const test = value => (
matchOrContain === 'match'
? value?.toLowerCase().includes(lowerValue)
: value?.toLowerCase() === lowerValue
);
return array.filter(
o => Object.values(o).some(test)
);
}
If you can't use optional chaining, then use the more vebose method and check to see if the value is truthy before calling a method on it:
const array = [{
category: "Amphibian",
common_name: "African Clawed Frog"
}, {
category: "Mammal",
common_name: "African Pygmy Hedgehog"
}, {
common_name: "African Spurred Tortoise"
}];
console.log(filterByKey(array, "category", "Mammal", "includes"))
function filterByKey(array, key, value, matchOrContain) {
const lowerValue = value.toLowerCase();
const test = value => value && (
matchOrContain === 'match'
? value?.toLowerCase().includes(lowerValue)
: value?.toLowerCase() === lowerValue
);
return array.filter(
o => Object.values(o).some(test)
);
}
Upvotes: 5
Reputation: 10204
On your code, on these parts,
array.filter(o => Object.keys(o).some(k => o[key].toLowerCase() === value.toLowerCase()));
array.filter(o => Object.keys(o).some(k => o[key].toLowerCase().includes(value
.toLowerCase())));
You have converted o[key]
to lowerCase even if it's not existed. So it throwed error.
You need to check the validation of o[key]
first and when valid, do the comparison as follows.
const array = [{
category: "Amphibian",
common_name: "African Clawed Frog"
}, {
category: "Mammal",
common_name: "African Pygmy Hedgehog"
}, {
common_name: "African Spurred Tortoise"
}];
function filterByKey(array, key, value, matchOrContain) {
if (matchOrContain == "match") {
var result = array.filter(o => Object.keys(o).some(k => o[key] && o[key].toLowerCase() === value.toLowerCase()));
} else if (matchOrContain == "includes") {
var result = array.filter(o => Object.keys(o).some(k => o[key] && o[key].toLowerCase().includes(value
.toLowerCase())));
}
return result;
}
console.log(filterByKey(array, "common_name", "African", "includes"));
console.log(filterByKey(array, "category", "Mammal", "includes"));
Upvotes: 2