21

I want to create a search filter for my data array.it has multiple objects and keys like this one,

[
    {
        "fname": "Jayne",
        "lname": "Washington",
        "email": "[email protected]",
        "gender": "female"
    },
    {
        "fname": "Peterson",
        "lname": "Dalton",
        "email": "[email protected]",
        "gender": "male"
    },
    {
        "fname": "Velazquez",
        "lname": "Calderon",
        "email": "[email protected]",
        "gender": "male"
    },
    {
        "fname": "Norman",
        "lname": "Reed",
        "email": "[email protected]",
        "gender": "male"
    }
]

I want search filter search anywhere on this array. ex: when I type input box I want to search anywhere inside an object. like fname,lname,email,gender

how can i do it? please help me

If I want to restrict the search for only first and last names how to do that?

3 Answers 3

40

You can keep a value filter in your component state and use that to see if it is contained as a substring in any of the array element properties.

Example

class App extends React.Component {
  state = {
    filter: "",
    data: [
      {
        fname: "Jayne",
        lname: "Washington",
        email: "[email protected]",
        gender: "female"
      },
      {
        fname: "Peterson",
        lname: "Dalton",
        email: "[email protected]",
        gender: "male"
      },
      {
        fname: "Velazquez",
        lname: "Calderon",
        email: "[email protected]",
        gender: "male"
      },
      {
        fname: "Norman",
        lname: "Reed",
        email: "[email protected]",
        gender: "male"
      }
    ]
  };

  handleChange = event => {
    this.setState({ filter: event.target.value });
  };

  render() {
    const { filter, data } = this.state;
    const lowercasedFilter = filter.toLowerCase();
    const filteredData = data.filter(item => {
      return Object.keys(item).some(key =>
        item[key].toLowerCase().includes(lowercasedFilter)
      );
    });

    return (
      <div>
        <input value={filter} onChange={this.handleChange} />
        {filteredData.map(item => (
          <div key={item.email}>
            <div>
              {item.fname} {item.lname} - {item.gender} - {item.email}
            </div>
          </div>
        ))}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Sign up to request clarification or add additional context in comments.

12 Comments

Searching for male will also match female. Need to use regex for this. ^1
@BhojendraNepal No need for regex. You can use startsWith if your just want to match from the beginning of the string, but OP didn't say anything about that, so I assumed includes type search was wanted.
@BhojendraNepal Not necessarily. female contains male, and if that is not what OP wants, he can tell me otherwise in a comment.
@Tholle oh I forgot one. I changed this line for when if search filed is empty x[key].toLowerCase().includes(searchText.toLowerCase()) || !searchText
If the data/JSON has non-string values like a boolean or float then this code will break. Convert the object into string like this: item[key].toString().toLowerCase().includes(lowercasedFilter)
|
0

Search filter for multiple objects key values and also highlights the search terms

Implemented two functions - highlighter and filterHandler.

filterHandler function filters the data based on the input given and then it sends the filtered data to highlighter function for highlighting.

highlighter function takes two arguments obj and input and it returns highlightable HTML code as a string.

class App extends React.Component {
  state = {
    input: "",
    fData: [{
        fname: "Jayne",
        lname: "Washington",
        email: "[email protected]",
        gender: "female"
      },
      {
        fname: "Peterson",
        lname: "Dalton",
        email: "[email protected]",
        gender: "male"
      },
      {
        fname: "Velazquez",
        lname: "Calderon",
        email: "[email protected]",
        gender: "male"
      },
      {
        fname: "Norman",
        lname: "Reed",
        email: "[email protected]",
        gender: "male"
      }
    ],
    data: [{
        fname: "Jayne",
        lname: "Washington",
        email: "[email protected]",
        gender: "female"
      },
      {
        fname: "Peterson",
        lname: "Dalton",
        email: "[email protected]",
        gender: "male"
      },
      {
        fname: "Velazquez",
        lname: "Calderon",
        email: "[email protected]",
        gender: "male"
      },
      {
        fname: "Norman",
        lname: "Reed",
        email: "[email protected]",
        gender: "male"
      }
    ]
  };


  handleChange = event => {
    this.setState({
      input: event.target.value
    }, this.filterHandler);
  };

  highlighter = (obj, lowercasedInput) => {
    let rawObj = obj.replace(`<span class='highlight'>`, '').replace(`</span>`, '');

    if (rawObj.indexOf(lowercasedInput) != -1) {
      const startIndex = rawObj.indexOf(lowercasedInput);
      const endIndex = startIndex - 1 + lowercasedInput.length;

      if (startIndex != 0) {
        return rawObj.slice(0, startIndex) + `<span class='highlight'>${lowercasedInput}</span>` + rawObj.slice(endIndex + 1, rawObj.length);
      } else {
        return rawObj.slice(0, startIndex) + `<span class='highlight'>${lowercasedInput}</span>` + rawObj.slice(endIndex + 1, rawObj.length);
      }
    } else {
      return rawObj
    }
  }


  filterHandler = () => {
    const {
      input,
      data
    } = this.state;
    const lowercasedInput = input.toLowerCase();

    const filteredData = data.filter(item => {
      return Object.keys(item).some(key =>
        item[key].toLowerCase().includes(lowercasedInput)
      );
    });

    let highlightFD = [];
    filteredData.map((values, index) => {
      highlightFD.push({ ...values
      });
    })


    if (lowercasedInput.trim().length > 0) {
      highlightFD.map((val, index) => {
        for (let key in val) {
          highlightFD[index][key] = this.highlighter(val[key].toLowerCase(), lowercasedInput);
        }
      });
    }

    this.setState({
      fData: highlightFD
    });

  }

  render() {
    const {
      input,
      fData
    } = this.state;



    return ( <
        div >
        <
        input value = {
          input
        }
        onChange = {
          this.handleChange
        }
        /> {
        fData.map(item => ( <div key ={item.email} className = "results" >
         <div dangerouslySetInnerHTML = {{__html: item.fname}}/>&nbsp;|&nbsp; 
         <div dangerouslySetInnerHTML = {{__html: item.lname}}/>&nbsp;|&nbsp; 
         <div dangerouslySetInnerHTML = {{__html: item.gender}}/>&nbsp;|&nbsp; 
          <div dangerouslySetInnerHTML = {{__html: item.email}}/>  
        </div >
        ))
      } </div>
  );
}
}

ReactDOM.render( < App / > , document.getElementById("root"));
.results {
  display: flex
}

span {
  background-color:black;
  color:white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Note: dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM. In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack.

To read more: https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml

Using Regular expressions :

class App extends React.Component {
  state = {
    input: "",
    fData: [{
        fname: "Jayne",
        lname: "Washington",
        email: "[email protected]",
        gender: "female"
      },
      {
        fname: "Peterson",
        lname: "Dalton",
        email: "[email protected]",
        gender: "male"
      },
      {
        fname: "Velazquez",
        lname: "Calderon",
        email: "[email protected]",
        gender: "male"
      },
      {
        fname: "Norman",
        lname: "Reed",
        email: "[email protected]",
        gender: "male"
      }
    ],
    data: [{
        fname: "Jayne",
        lname: "Washington",
        email: "[email protected]",
        gender: "female"
      },
      {
        fname: "Peterson",
        lname: "Dalton",
        email: "[email protected]",
        gender: "male"
      },
      {
        fname: "Velazquez",
        lname: "Calderon",
        email: "[email protected]",
        gender: "male"
      },
      {
        fname: "Norman",
        lname: "Reed",
        email: "[email protected]",
        gender: "male"
      }
    ]
  };


  handleChange = event => {
    this.setState({
      input: event.target.value
    }, this.filterHandler);
  };

  highlighter = (obj, lowercasedInput) => {
    let rawObj = obj.replace(`<span class='highlight'>`, '').replace(`</span>`, '');

    if (rawObj.indexOf(lowercasedInput) != -1) {
      const startIndex = rawObj.indexOf(lowercasedInput);
      const endIndex = startIndex - 1 + lowercasedInput.length;

      if (startIndex != 0) {
        return rawObj.slice(0, startIndex) + `<span class='highlight'>${lowercasedInput}</span>` + rawObj.slice(endIndex + 1, rawObj.length);
      } else {
        return rawObj.slice(0, startIndex) + `<span class='highlight'>${lowercasedInput}</span>` + rawObj.slice(endIndex + 1, rawObj.length);
      }
    } else {
      return rawObj
    }
  }


  filterHandler = () => {
    const {
      input,
      data
    } = this.state;
    const lowercasedInput = input.toLowerCase();

    const filteredData = data.filter(item => {
      return Object.keys(item).some(key =>{
         const regex= new RegExp(`^${lowercasedInput.trim()}`,'i');
            return regex.test(item[key].toLowerCase()) ;
         }
      );
    });

    let highlightFD = [];
    filteredData.map((values, index) => {
      highlightFD.push({ ...values
      });
    })


    if (lowercasedInput.trim().length > 0) {
      highlightFD.map((val, index) => {
        for (let key in val) {
          highlightFD[index][key] = this.highlighter(val[key].toLowerCase(), lowercasedInput);
        }
      });
    }

    this.setState({
      fData: highlightFD
    });

  }

  render() {
    const {
      input,
      fData
    } = this.state;



    return ( <
        div >
        <
        input value = {
          input
        }
        onChange = {
          this.handleChange
        }
        /> {
        fData.map(item => ( <div key ={item.email} className = "results" >
         <div dangerouslySetInnerHTML = {{__html: item.fname}}/>&nbsp;|&nbsp; 
         <div dangerouslySetInnerHTML = {{__html: item.lname}}/>&nbsp;|&nbsp; 
         <div dangerouslySetInnerHTML = {{__html: item.gender}}/>&nbsp;|&nbsp; 
          <div dangerouslySetInnerHTML = {{__html: item.email}}/>  
        </div >
        ))
      } </div>
  );
}
}

ReactDOM.render( < App / > , document.getElementById("root"));
.results {
  display: flex
}

span {
  background-color:black;
  color:white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Comments

0
fData.filter((person) => {
  return object
    .value(person)
    .join('')
    .toLowerCase()
    .include(searchinput.toLowerCase())
})

Here searchinput is the value you are typing in your input that is controlled by state.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.