Robert Hung
Robert Hung

Reputation: 165

How do I allow filter booleans to be non-mutually exclusive?

I'm trying to filter my results using an object with values that are either true or false. However, these filters are not mutually exclusive, meaning more than one can be true.

The code shown only allows one filter to work, I assume I need to figure out a way to make showData dynamic but I'm not too sure how.

const filters = {
  letter: {
    A: false,
    B: false,
    C: false,
    D: false,
    E: false
  },
  number: {
    1: false,
    2: false,
    3: false,
    4: false
  },
  //...
};

const data = [
  {
    letter: "A",
    number: "1",
  },
  {
    letter: "B",
    number: "1",
  },
  {
    letter: "B",
    number: "2",
  },
  //...
],

const results = data.map((result, index) => {
  let showData = true;

  if (filters.letter.A) showData = result.letter === "A";
  if (filters.letter.B) showData = result.letter === "B";
  //...

  return (showData && result)
})}

An example of expected output is if both filters.letter.A and filters.letter.B were true, then results would return an array of objects matching these two filters.

Upvotes: 1

Views: 325

Answers (2)

Serge Ageyev
Serge Ageyev

Reputation: 419

You probably need that any condition should set showDara, but not clear it.

Simple solution:

//...
if (letter.A) showData = showData || data.letter ===‘A’;
if (letter.B) showData = showData || data.letter ===‘B’;
//...

Advanced:

If I correct in guessing your data, you may simplify the code.

This code will work in case data.letter and data.number is reasonable sanitized values that not interfere with build in or inherited properties:

//...
if(letter[data.letter] === true) showData = true;
if(number[data.number] === true) showData = true;
//...

More advanced:

This code looks more correct, but bit more complex: (Using hasOwnProperty method to check that property defined in object itself and not inherited from parent object):

//...
if(letter.hasOwnProperty(data.letter) && letter[data.letter] === true) showData = true;
if(number.hasOwnProperty(data.number) && number[data.number] === true) showData = true;
//...   

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 371049

Construct an array of the truthy keys in filters.letter in advance, and then you can set showCard based on whether the .letter of the current card being iterated over is included in that array:

const trueLetterKeys = Object.entries(filters.letter)
  .filter(([, val]) => val)
  .map(([key]) => key);
// ...
{data.map(({ letter }, index) => {
  const showCard = trueLetterKeys.includes(letter);
  // ...

Doesn't matter when there aren't many items, but to reduce complexity you could use a Set of truthy keys instead of an array, since a Set's .has is quicker than an array's .includes:

const trueLetterKeys = new Set(
  Object.entries(filters.letter)
    .filter(([, val]) => val)
    .map(([key]) => key)
);
// ...
{data.map(({ letter }, index) => {
  const showCard = trueLetterKeys.has(letter);
  // ...

Upvotes: 2

Related Questions