1

I am trying to highlight the remaining of a word if the text value from an input includes the start of the word. For example, we have a string of "Nutrition is great!", and if the user types in "Nutr" then I would like for "Nutrition" to be highlighted. I am having quite a lot of difficulty with this and was wondering if it's possible to substring to the next available whitespace? Or if anyone could give me any pointers for a different/better approach.

I have taken some inspiration from This post but unfortunately, it doesn't match the full word as I'd like.

I have created a sandbox to demonstrate my example, you'll notice that if you type in "Nutr" that only 2 options get highlighted when all 3 options should if possible?

https://codesandbox.io/s/dry-wind-17mko

zabop
  • 6,750
  • 3
  • 39
  • 84
mark
  • 235
  • 3
  • 11
  • I see two lower case n (nutritional and nutrition) and one upper case N (Nutritional). If I type Nut it highlights the upper case word as desired, if I type nut it highlights the lower case words. Is that what you would like to change? – Christian Fritz Jan 06 '21 at 15:46
  • @Mark: Try this https://codesandbox.io/s/highlighting-z216x .. I guess we also need to improve code a bit – Imran Rafiq Rather Jan 06 '21 at 15:46
  • @ChristianFritz ah! I didn't notice that! I should check against toLowerCase() to get this to match, but what I am trying to achieve is that the whole word should highlight if the beginning input matches? If that makes sense? So typing "nutr" should highlight all instances of "nutrition" – mark Jan 06 '21 at 15:50
  • @ImranRafiqRather thanks for your response, it is very close to what I expect, but can we not highlight the "products" part and only "nutrition"? – mark Jan 06 '21 at 15:51
  • @mark: Ya Working on that :) just a moment please – Imran Rafiq Rather Jan 06 '21 at 15:54
  • @ImranRafiqRather thank you very much, sorry I added a comment in the main post for easier readability as well :) – mark Jan 06 '21 at 15:56
  • @mark: It's DONE Mate !!! Have added the Logic to highlight the term only :) Do Accept the Answer my friend :) Thanks – Imran Rafiq Rather Jan 06 '21 at 17:10
  • @mark - Can't believe you accepted an answer that does not work. Use your original input and output criteria and you will discover that answer highlights the period at the end of the sentence. It also shifts all of the strings to uppercase - unlikely what you want to achieve. You should probably re-evaluate the selection using _your_ original inputs and you will see it doesn't work properly. Then review my answer and you will see that it preserves the integrity of the original text and only highlights the matched word. – Randy Casburn Jan 07 '21 at 14:26
  • 1
    @mark - cleaned up the code and added the use case for removing a highlight when the search string is no longer found. In other words, in the search box type `nutr`, followed by any character other than `I` and it will clear the highlight. – Randy Casburn Jan 07 '21 at 15:42

3 Answers3

1

Comparison has to be based on String either being uppercase or lower case so that we can select the text String irrespective of being upper case of lower case.

UPDATE:

Also we need to select only the term based on match but not full length of text in the span.

UPDATED CODESANDBOX: https://codesandbox.io/s/highlighting-z216x

Logic to get the specific text updated to work dynamically.

Code Changes in useEffect() in Result.js

  useEffect(() => {
    console.log(searchTerm);
    if (titleRef.current) {
      let resultsText = titleRef.current.textContent.toUpperCase();
      const index = resultsText.toUpperCase().indexOf(searchTerm);
      
      const text = resultsText.substr(index, resultsText.length).split(" ")[0];
      if (index >= 0) {
        resultsText =
          resultsText.substring(0, index) +
          "<span>" +
          text +
          "</span>" +
          resultsText.substring(index + text.length);
        titleRef.current.innerHTML = resultsText;
      }
    }
  }, []);

And in App.js we need to make sure to pass searchTerm as uppercase props

    <Result
      text="This is nutritional value"
      searchTerm={searchTerm.toUpperCase()}
    />
Imran Rafiq Rather
  • 7,677
  • 1
  • 16
  • 35
  • Thank you for your response and upvoted for correcting my case check. Is it possible to only highlight the word "Nutrition" and not anything afterwards? This is what I was trying to ask in the question when I said "next whitespace" to try and explain my problem – mark Jan 06 '21 at 15:55
  • Checking the code Logic... Will need a basic change.. Just give me moment please :) – Imran Rafiq Rather Jan 06 '21 at 15:56
1

You have a few issues in that others have pointed out about upper/lower case. You are also including the period at the end of the sentence, which is unlikely your intent.

This solution doesn't require changing the case of the input or anything.

I would like to offer a simpler approach using Regular expressions and the .match() method from the String Object.

This will allow a case insensitive match while only highlighting the word. In the code below, you'll see the matched searched word placed into the HTML with a simple call to .replace() adding the <span> tags.

The match is done based upon finding the typed characters and then finding the word boundary (the space you mentioned in your question).

if (titleRef.current) {
  let resultsText = titleRef.current.innerHTML;
  const regex = new RegExp("(?=" + searchTerm + ")\\w*", "i");
  const found = resultsText.match(regex);
  if (found) {
    titleRef.current.innerHTML = resultsText.replace(found[0],`<span>${found[0]}</span>`);
  }
}

There is one remaining problem. If the search no longer matches (say you type 'nutrdddd', the original match remains highlighted. So to overcome this, you'll need to remove the span tags and I'll leave that up to you.

Hope this is helpful. Here is the CodeSandBox

Randy Casburn
  • 13,840
  • 1
  • 16
  • 31
0

Well, first what you can do is you need to change your string and input both to either Lowercase or Uppercase so that both will be compared on the same basis. rest all is fine you can check using .includes() method and you can trim your string using .trim() method as then can only highlight the desired the word.

Karan Singh
  • 183
  • 1
  • 9