4

I have made a function which highlights matching words in a div. but if there are two identical words separated by a different word then only the first word is highlight. so for example if the search criterion was the word "burn", and in the text was the sentence "burn baby burn", I would want it to highlight both "burn"'s. this jsFiddle demonstrates how it only highlights the first "burn". Here is the code below also.

if ($('#search').val().length !== 0) { $('.searchable').each(function() { $(this).html($(this).html().replace($('#search').val(), "<span class = 'highlight'>" + $('#search').val() + "</span>")); }); }
.highlight { font-weight: bold; color: green; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <input id = "search" type ="text" value = "burn"> <div class="searchable">burn baby burn</div>

5 Answers 5

12

You can pass a regular expression into replace() instead of the string, with the g modifier to make replace perform a global match.

if($('#search').val().length !== 0){ $('.searchable').each(function(){ var search_value = $("#search").val(); var search_regexp = new RegExp(search_value, "g"); $(this).html($(this).html().replace(search_regexp,"<span class = 'highlight'>"+search_value+"</span>")); }); } 
Sign up to request clarification or add additional context in comments.

Comments

9
  1. Take care of regex special characters.

  2. Maintain uppercase & lowercase.

So taking care of above things with case insensitive search (in most cases, this is desired; otherwise just remove "i"), here is the final code...

if ($('#search').val().length !== 0) { $('.searchable').each(function() { //Handle special characters used in regex var searchregexp = new RegExp($("#search").val().replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), "gi"); //$& will maintain uppercase and lowercase characters. $(this).html($(this).html().replace(searchregexp, "<span class = 'highlight'>$&</span>")); }); } 

And a fiddle.

1 Comment

This answer also handles special characters in the search string.
1

Here's a working jsfiddle for you. Basically, get the text from the div, split it on space, loop through the words and see if one matches.

var term = $('#search').val().trim().toLowerCase(); if (term.length > 0) { var source = $('.searchable').text(); var words = source.split(' '); var output = ''; $.each(words, function(idx, word) { if (term === word.toLowerCase()) { output += '<span class="highlight">' + word + '</span> '; } else { output += word + ' '; } }); $('.searchable').html(output); } 

Comments

0

Use regular expression with :

  • global 'g' flag to replace all the matches
  • ignore case 'i' to match all cases

Do not forget to escape special characters

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

const SEARCH_VALUE = $("#search").val().trim(); if (SEARCH_VALUE.length > 0) { $('.searchable').each(function() { const DIV_TEXT_CONTENT = $('.searchable').text(); const SPLIT_CONTENT = DIV_TEXT_CONTENT.split(" "); SPLIT_CONTENT.forEach((word, index) => { const SEARCH_REGEXP = new RegExp(escapeRegExp(SEARCH_VALUE), "gi") if (SEARCH_REGEXP.test(word)) $(this).html($(this).html().replace(SEARCH_REGEXP, "<span class = 'highlight'>" + word + " </span>")); }); }) } function escapeRegExp(text) { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); }
.highlight { font-weight: bold; color: green; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <input id="search" type="text" value="BuRn"> <div class="searchable">burn baby burn</div>

Comments

0

The existing answers focus on innerHTML manipulation. It's possible to do entirely with DOM APIs:

function highlight(term) { // Select all Elements. There is no method to query all Nodes directly. for (const element of document.querySelectorAll("*")) { // Skip element if it doesn't contain target string if (!element.textContent.includes(term)) continue; // Traverse each node by inspecting the childNodes of every element for (const child of element.childNodes) { // Skip node if its not a text node if (child.nodeType !== Node.TEXT_NODE) continue; // Skip node if it doesnt contain our target string if (!child.textContent.includes(term)) continue; // We want to break up the contents into chunks // of text which don't need to be highlighted // You can get creative here if you want // to use more term advanced matching const textNodes = child.data.split(term).map(substr => { return document.createTextNode(substr); }); // We don't want to modify the overall structure of the DOM // a fragment lets us group multiple nodes together without // bundling it under another new node const fragment = document.createDocumentFragment(); // Populate the new fragment for (const node of textNodes) { // Add every text node to the new node fragment.appendChild(node); // Interweave the term in between them within a span const el = document.createElement("span") el.textContent = term; // Add some styling el.style.backgroundColor = 'yellow'; fragment.appendChild(el); } // Remove extra term that was // generated the interweaving fragment.removeChild(fragment.lastChild); // Swap current child node for new fragment element.replaceChild(fragment, child); } } } // highlight a word highlight("JavaScript") 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.