4

How can I write a javascript/jquery function that replaces text in the html document without affecting the markup, only the text content?

For instance if I want to replace the word "style" with "no style" here:

<tr>
<td style="width:300px">This TD has style</td>
<td style="width:300px">This TD has <span class="style100">style</span> too</td>
</tr>

I don't want the replacement to affect the markup, just the text content that is visible to the user.

2 Answers 2

13

You will have to look for the text nodes on your document, I use a recursive function like this:

function replaceText(oldText, newText, node){ 
  node = node || document.body; // base node 

  var childs = node.childNodes, i = 0;

  while(node = childs[i]){ 
    if (node.nodeType == 3){ // text node found, do the replacement
      if (node.textContent) {
        node.textContent = node.textContent.replace(oldText, newText);
      } else { // support to IE
        node.nodeValue = node.nodeValue.replace(oldText, newText);
      }
    } else { // not a text mode, look forward
      replaceText(oldText, newText, node); 
    } 
    i++; 
  } 
}

If you do it in that way, your markup and event handlers will remain intact.

Edit: Changed code to support IE, since the textnodes on IE don't have a textContent property, in IE you should use the nodeValue property and it also doesn't implements the Node interface.

Check an example here.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks a lot @CMS, you helped me resolve this problem: stackoverflow.com/questions/1512053/…
Watch out for 2011 builds of MSIE9 - they have node.textContent support, but if you try and assign a new value using node.textContent = ... then those builds crash the entire browser with A problem with this website caused Internet Explorer to close. Later builds (2012) seem OK. The workaround is to assign with node.nodeValue = ... inside the if (node.textContent) part of the loop regardless and just forget doing it with textContent.
Why won't you use node.data for all browsers?
4

Use the :contains selector to find elements with matching text and then replace their text.

$(":contains(style)").each(function() {
  for (node in this.childNodes) {
    if (node.nodeType == 3) { // text node
      node.textContent = node.textContent.replace("style", "no style");
    }
  }
});

Unfortunately you can't use text() for this as it strips out HTML from all descendant nodes, not just child nodes and the replacement won't work as expected.

1 Comment

Don't use a "for...in" to loop through an array-like-object.. a traditional for/while loop is much faster.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.