Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Add a span class to a word in a div, preserving existing HTML

I’m working on a small project that requires me to take a information from inside a div, wrap all instances of a certain word in a classed span tag, and then put everything back to the div again in the correct place.

My JS is ok in grabbing the text I need and splitting it onto an array, but am lost on where to go from here.
For example, let’s say the word is "needle". Here is my code:

function needleTest(){
    var text_string = document.getElementById('haystack').innerHTML;
    var text_array = text_string.split(' ');
    for (let i = 0; i < text_array.length; i++) {
        if(text_array[i]=='needle'){
            return "<span class='needle'>" + text_array[i] + "</span>";
        }else{
            return text_array[i];
        }
    }
}
.needle{color:red}
<div id='haystack' contentEditable='true'>
There is a <strong>needle</strong> in this <a href='#'>haystack</a>
</div>
<button onclick='needleTest()'>
Click
</button>

What should happen is the script should grab the contents of the div, split it on the spaces, then loop through every element in the array.
It should completely ignore any hyperlinks (so elements starting <a) and ignore images (elements starting <img). For all other elements it should hunt for the word "needle" and, if found, wrap it in the class. ‘Needle’ may or may not have HTML tags around it. If it does, they should be preserved, and the new class added to to wrap everything else.
Finally, everything should then go back into the original div.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

So, in this non working example, clicking the button should result in the following being put back into the div:

There is a <span class='needle'><strong>needle</strong></span> in this <a href='#'>haystack</a>

>Solution :

You can try recursive approach to traverse the DOM tree, identifying text nodes and wrapping the word (needle) in a span with the class (needle).

Demo:

function needleTest() {
  //start processing the DOM from the 'haystack' div
  processNode(document.getElementById('haystack'));
}

//recursive function to process each node in the DOM tree
function processNode(node) {
  //check if the current node is a text node
  if (node.nodeType === Node.TEXT_NODE) {
      //split the text into words and create an array
      const words = node.nodeValue.split(' ').map(word => 
          //check if the word is 'needle', if yes, wrap it in a span with the class 'needle'
          word.toLowerCase() === 'needle' ? `<span class='needle'>${word}</span>` : word
      );

      //create a new span element and set its innerHTML to the joined words
      const spanWrapper = document.createElement('span');
      spanWrapper.innerHTML = words.join(' ');

      //replace the current text node with the new span element
      node.replaceWith(spanWrapper);
  } else if (node.nodeType === Node.ELEMENT_NODE && node.nodeName !== 'A' && node.nodeName !== 'IMG') {
      //if the current node is an element (excluding 'A' and 'IMG' elements)
      //recursively process each child node of the current element
      node.childNodes.forEach(childNode => processNode(childNode));
  }
}
.needle { color: red; }
<div id='haystack' contentEditable='true'>
    There is a <strong>needle</strong> in this <a href='#'>haystack</a>
</div>

<button onclick='needleTest()'>Click</button>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading