Home > Back-end >  Nested Filtering in ReactJS
Nested Filtering in ReactJS

Time:07-08

I have an requirement to build a search component which will filter data from the below data structure. The Data structure is as follows,

const data = {
  details: {
    Alex: {
      name: 'ABC1',
      icon: shopIcon,
      content: [{
          risk: 0,
          name: 'basketball',
          value: ["str1", "str2"]
        },
        {
          risk: 0,
          name: 'tennis',
          value: []
        }
      ]
    },
    Leon: {
      name: 'ABC2',
      icon: shopIcon,
      content: [{
          risk: 0,
          name: 'Cricket',
          value: ["str1"]
        },
        {
          risk: 0,
          name: 'swimming',
          value: []
        }
      ]
    },
    Harsha: {
      name: 'ABC2',
      icon: shopIcon,
      content: [{
          risk: 0,
          name: 'baseball',
          value: ["str1"]
        },
        {
          risk: 0,
          name: 'hockey',
          value: []
        }
      ]
    }
  }
}

I want to filter the content in above type data from both the keys in details and the name in content.

For Example:- if user type 'le' both the Alex and Leon data should display.

search Field Text :- "le"
output :- 

Alex: {
    name: 'ABC1',
    icon: shopIcon,
    content: [{
        risk: 0,
        name: 'basketball',
        value: ["str1", "str2"]
      },
      {
        risk: 0,
        name: 'tennis',
        value: []
      }
    ]
  },
  Leon: {
    name: 'ABC2',
    icon: shopIcon,
    content: [{
        risk: 0,
        name: 'Cricket',
        value: ["str1"]
      },
      {
        risk: 0,
        name: 'swimming',
        value: []
      }
    ]
  },

Search Text field :- ball
output :- 

Alex: {
    name: 'ABC1',
    icon: shopIcon,
    content: [{
      risk: 0,
      name: 'basketball',
      value: ["str1", "str2"]
    }]
  },
  Harsha: {
    name: 'ABC2',
    icon: shopIcon,
    content: [{
      risk: 0,
      name: 'baseball',
      value: ["str1"]
    }]
  }

I was only able to achieve the search only by one part. Either with the main key value or with the content name value. Was not able to achieve both at once. Here is the code that I used to achieve the search with the main key value. Any Explanation on what I am missing in here so that I can achieve search in both the places at once ?

Object.entries(data.details).filter((k) => {
    let searchFieldText = searchText.toLowerCase();

    if (searchFieldText === "") {
      return k;
    } else if (k[0].toLowerCase().includes(searchFieldText)) {
      return k;
    }

  }).map(([keys, values]) => ( 
  <> 
      <p>{values.name}</p>
      {values.content.map((contents) => { 
        <p> {contents.name} </p>
       }) 
  </>

))

CodePudding user response:

If you want to search both the key value and the name in the content, you can do something like this:

Object.entries(data.details).filter((k) => {
    let searchFieldText = searchText.toLowerCase();

    if (searchFieldText === "") {
      return k;
    } else if (k[0].toLowerCase().includes(searchFieldText) || k[1].content.some(i => i.name.toLowerCase().includes(searchFieldText))) {
      return k;
    }

  }).map(([keys, values]) => ( 
  { /* ... */}
))

CodePudding user response:

Why this method:

  • Search for the match in key and name in the content array (value.content[].name)
  • The hole process done in one loop

If you want an object in return try this

const checkIncludes = (a, b) => {
  return a.toLowerCase().includes(b.toLowerCase());
};

const output = Object.entries(data.details).reduce((a, b) => {
  if (!searchText) {
    a[b[0]] = b[1];
  }
  if (checkIncludes(b[0], searchText)) {
    a[b[0]] = b[1];
  }
  if (b[1]?.content.some((e) => checkIncludes(e.name, searchText))) {
    a[b[0]] = b[1];
  }
  return a;
}, {});


console.log(output);
// {
//   Alex: { name: 'ABC1', icon: '', content: [ [Object], [Object] ] },
//   Leon: { name: 'ABC2', icon: '', content: [ [Object], [Object] ] }
// }

If you want an array in return try this

const checkIncludes = (a, b) => {
  return a.toLowerCase().includes(b.toLowerCase());
};

const output = Object.entries(data.details).reduce((a, b) => {
  b[1].key = b[0];
  if (!searchText) {
    a.push(b[1]);
  }
  if (checkIncludes(b[0], searchText)) {
    a.push(b[1]);
  }
  if (b[1]?.content.some((e) => checkIncludes(e.name, searchText))) {
    a.push(b[1]);
  }
  return a;
}, []);

console.log(output);
//  [
//     {
//       name: 'ABC1',
//       icon: '',
//       content: [ [Object], [Object] ],
//       key: 'Alex'
//     },
//     {
//       name: 'ABC2',
//       icon: '',
//       content: [ [Object], [Object] ],
//       key: 'Leon'
//     }
//  ]

Create react element

output.map((each) => ( 
    <div key={each.key}> 
      <p>{each.name}</p>
      {each.content.map((contents, i) => { 
        <p key={i}> {contents.name} </p>
       })
    </div>
  ))
  • Related