Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

highlight searching text on type react

I try to highlight text in a input on typing, I use two method in this case. As I understand I need return on search something like this: <mark>${item}<mark/>

fuzzyContains = (text, search) => {
        debugger
        if (!text)
            return false
        if (!search)
            return true

        search = search.toLowerCase()
        text = text.toString().toLowerCase()

        let previousLetterPosition = -1

        return search.split('').every(s => {
            debugger
            previousLetterPosition = text.indexOf(s, previousLetterPosition + 1)

            return previousLetterPosition !== -1
        })
    }

    handleSearch = search => {
        const {data} = this.state
        debugger
        let filteredData = data.filter(x => Object.keys(x).some(key => {
            debugger
            this.fuzzyContains(x[`<mark>${key}<mark/>`], search)}))

        this.setState({filteredData, search})
    }
like image 332
Palaniichuk Dmytro Avatar asked May 05 '26 09:05

Palaniichuk Dmytro


1 Answers

The code you provide is too little to understand what's actually going on in your app. Instead, I have made a simple example below.


In the following snippet I start by creating an application with a fixed text and an input element. The input element has a listener that has an onChange trigger. Whenever you type something, the changeInput function is fired.

The function starts by getting the innerText of the related DOM node where the text is printed. It then tries to find your entered substring with indexOf. If there's a match, we split the string into three pieces (the matching text, and the substrings before and after that matching text, if any).

If there is no match, we reset the text back to the initial value.

The whole thing is then entered into an array; the 1st and 3rd items are plain strings, whereas the 2nd item (the match) is a React Element of type strong which is used to highlight the matching text.

class MyApp extends React.Component {
  constructor() {
    super();
    this.initialText = "Lorem ipsum dolor sit amet";
    this.state = {
      text: this.initialText,
      inputValue: ""
    };
  }
  changeInput = (e) => {
    let value = e.target.value;
    let txt = document.getElementById("myText").innerText;
    let idx = txt.indexOf(value);
    if(idx >= 0) {
      let newText = [txt.substring(0, idx), <strong>{txt.substring(idx, idx + value.length)}</strong>, txt.substring(idx + value.length)];
      this.setState({inputValue: value, text: newText});
    } else {
      this.setState({inputValue: value, text: this.initialText});
    }    
  }
  render() {
    return (
      <div>
        <p id="myText">{this.state.text}</p>
        <input onChange={this.changeInput} value={this.state.inputValue} />
      </div>
    );
  }
}

ReactDOM.render(<MyApp />, document.getElementById("app"));
strong {
  background: red;
  color: white;
  font-weight: inherit;
}
<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="app"></div>

Note that this can be done with using refs if you prefer. If you want to avoid DOM lookups and the use of refs, you could always use 2 state variables; one that holds the resulting JSX and one that holds the plain text representation.

Also note that this will only highlight the first matching substring. For example, if you had the string: "Lorem ipsum, Lorem ipsum", and you searched for "Lorem", only the first occurrence of that word would be highlighted. If you want multiple hightlights, you could try using some kind of regex.

like image 67
Chris Avatar answered May 08 '26 21:05

Chris



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!