Search code examples
javascripthtmlreplacegetelementsbytagname

How do you avoid editing tags inside of tags when replacing characters inside of a tag


So lets say you have HTML that looks something like this:

<p>This text is <b>bold</b></p>

and this Javascript:

var obs = document.getElementsByTagName("p");
var obsreplace = obs[0].innerHTML.replace(/b/gi, "g");
obs[0].innerHTML = obsreplace;

This will change the HTML to this:

<p>This text is <g>gold</g></p>

But what if I want to change it to:

<p>This text is <b>gold</b></p>

and leave the bold tags unchanged?


Solution

  • You'll want to use childNodes, and run your replace against each of those. That will capture text nodes separately from elements. By recursively looping through each child element until there are only text nodes left, you can safely run your replace command against all text in the element.

    function safeReplace(elem, replaceFn){
      let nodes = elem.childNodes, i = -1
      while(++i < nodes.length){
        let node = nodes[i]
        if(node.nodeType == 3){ //signifies a text node
          node.textContent = replaceFn(node.textContent)
        } else {
          safeReplace(node, replaceFn)
        }
      }
    }
    document.querySelector('button').addEventListener('click', function(){
      safeReplace(document.getElementById('testDiv'), function(str){
        return str.replace(/e/gi, '_E_')
      })
    })
    <div id="testDiv">
    This div has outer content, as well as <p>a paragraph containing a <span>spanned text</span> in the middle</p>More text.</div>
    
    <button>Replace Text</button>