user13349816
user13349816

Reputation:

Filter array of objects based on the input passed: Javascript

I have an array of objects with the following structure

arr = [ { name: "abc" , items: ["itemA","itemB","itemC"], days :138} ,
        { name: "def" , items: ["itemA1","itemB2","itemC1"], days :157} ,
        { name: "hfg" , items: ["itemAN","itemB7","itemC7"], days :189} ]

This array needs to be filtered based on the search input passed. I was able to achieve the same for the name , where days is not getting filtered.

Also can someone help how to search across items array too so it filters the rows based on input passed

This is what I have tried

  handleSearch = (arr, searchInput) => {
    let filteredData= arr.filter(value => {
      return (
        value.name.toLowerCase().includes(searchInput.toLowerCase()) ||
        value.days.toString().includes(searchInput.toString())
      );
    });
    console.log(filteredData);
    //this.setState({ list: filteredData });
  }


Upvotes: 2

Views: 15411

Answers (2)

boehm_s
boehm_s

Reputation: 5544

You can use Array#some and then perform the same kind of match that you've already done :

The some() method tests whether at least one element in the array passes the test implemented by the provided function. It returns a Boolean value.

  handleSearch = (arr, searchInput) => {
    const filteredData = arr.filter(value => {
      const searchStr = searchInput.toLowerCase();
      const nameMatches = value.name.toLowerCase().includes(searchStr);
      const daysMatches = value.days.toString().includes(searchStr);
      const oneItemMatches = value.items.some(item => item.toLowerCase().includes(searchStr));

      return nameMatches || daysMatches || oneItemMatches;
    });
    console.log(filteredData);
    //this.setState({ list: filteredData });
  }

Upvotes: 3

M0nst3R
M0nst3R

Reputation: 5283

As your search value can apply to all fields in your data array, you can combine the values together in one array (row by row) and perform the search in one place.

To do that, I've provided a snippet below that will filter the original array checking each object's values after the transformations. These involve using Object.values() to get the values of the object in an array, since this array is nested, we can make use of Array.flat() to flatten it into just the strings and numbers, finally call Array.some() to check if one of the values partially includes the search value (after they've both been lowercase-d).

const arr = [
    { name: "abc" , items: ["itemA","itemB","itemC"], days: 138 },
    { name: "def" , items: ["itemA1","itemB2","itemC1"], days: 157 },
    { name: "hfg" , items: ["itemAN","itemB7","itemC7"], days: 189 }
];

const handleSearch = (arr, searchInput) => (
    arr.filter((obj) => (
        Object.values(obj)
              .flat()
              .some((v) => (
                  `${v}`.toLowerCase().includes(`${searchInput}`.toLowerCase())
              ))
    ))
);

console.log('"A1" =>', JSON.stringify(handleSearch(arr, 'A1')));
console.log('189 =>', JSON.stringify(handleSearch(arr, 189)));
console.log('"nope" =>', JSON.stringify(handleSearch(arr, 'nope')));

NOTE: This approach has one obvious flaw, it will seach through numbers as strings, meaning that providing 89 as the search value will still return the second element.

Upvotes: 1

Related Questions