Search code examples
javascripthtmlcssangularjsinnerhtml

innerHtml.replace replaces tags and not just text


I currently try to replace certain words from an utterance with a <span>WORD</span element. I get the start and end indices from the words from the backend. An utterance can have several words which will be replaced. So I just iterate over the array of words to replaced and try to replace the words in the utterance.

However, I tried doing it with innerHtml.replace(word, <span>word</span>). The problem here is, that when for example the second word is 'sp' the sp of the tag of the first word is replaced instead of the word 'sp' in my utterance.

I then tried to replace the word my putting in the start and end index of the word (which I thought would solve the problem). But it seems like if the start and end index points on 'sp' it still replaces the part of span and not the word I wanted to replace.

So, I am looking for a way to replace only words in an utterance and not the HTML elements with the <span>WORD</span>.

My Code right now:

var label = document.getElementById('match-text' + index);
      label.innerHTML = label.innerHTML.replace(label.innerText.substring(entity.start, entity.end),'<span ng-click="showEntityDetailsPage($event, ' + index + ', ' + entityIndex + ')" style="background-color:'
      + color + '; border: 3px solid ' + borderColor + ';" class="highlighted-entities">' + label.innerText.substring(entity.start, entity.end) + '</span>');
      $compile(label)($scope);

Solution

  • Further to my comment, here is how I would implement that. In this example the anchor tag's html attribute contains "oo" and so does the tfoot tag, and they do not get changed.

    function replaceText(obj, search, wrapElement, elementClass) {
      switch (obj.nodeType) {
        case 3: // it's a text node
          if (obj.nodeValue.indexOf(search) > -1) {
            var bits = obj.nodeValue.split(search);
            var nextSib = obj.nextSibling;
            obj.nodeValue = bits[0];
            for (var i=1; i < bits.length; i++) {
              var el = document.createElement(wrapElement);
              el.className = elementClass;
              el.innerHTML = search;
              var tn = document.createTextNode(bits[i]);
              if (nextSib) {
                obj.parentNode.insertBefore(tn, nextSib);
                obj.parentNode.insertBefore(el, tn);
              } else {
                obj.parentNode.appendChild(tn);
                obj.parentNode.insertBefore(el, tn);
              }
            }
            return 2*(bits.length-1);
          }
        break;
        default: // it's not a text node
          for (var i=0; i < obj.childNodes.length; i++) {
            var j = replaceText(obj.childNodes[i], search, wrapElement, elementClass);
            if (j) i+=j;
          }
        break;
      }
    }
    
    replaceText(document.getElementById('starthere'), "oo", "span", "myspanclass");
    .myspanclass {
      color: red;
    }
    <div id='starthere'>Noonhour
      <span>Boondoggle
        <a href="http://google.com">Google</a>
      </span>
      The Moon is a Balloon
      <table><tfoot><tr><th>oops!</th></tr></tfoot></table>
    </div>