user14479722
user14479722

Reputation:

Make the array.filter filter null values as well

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

Answers (2)

CertainPerformance
CertainPerformance

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

Derek Wang
Derek Wang

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

Related Questions