Reputation: 249
I'm trying to replace all text in between tags and I want to know the fastest way of doing so.
An example would be trying to replace all text with the arbitrary string helloWorld, so that this:
<div>
<div>
RandomText1
<div>
RandomText2
</div>
</div>
</div>
Becomes this:
<div>
<div>
helloWorld
<div>
helloWorld
</div>
</div>
</div>
My current approach would be :
This to me would be really slow, especially trying to do this for a large document and having to repeat the process many times. Is there a faster way?
Upvotes: 7
Views: 4291
Reputation: 43910
The nodeIterator
is pretty fast. It has no problems with nested nodes no matter how deeply they're buried. Note: added red text that's 6 levels down. Details commented in Snippet.
SNIPPET
/* Create a custom filter which will...
||...the 3rd parameter of createNodeIterator method...
*/
function textFilter(node) {
// if .nodeType is 3 (3 is text, 1 is element)
if (node.nodeType === 3) {
// Set .nodeValue to 'hellowWorld'
node.nodeValue = 'helloWorld';
// Return NodeFilter object to accept node
return NodeFilter.FILTER_ACCEPT;
}
// Otherwise ignore node
return NodeFilter.FILTER_SKIP;
}
function findText() {
// Reference the rootNode
var content = document.querySelector('body');
/* Create nodeIterator passing
|| content or rootNode
|| NodeFilter object or WhatToShow property
|| Custom filter function
*/
var iterator = document.createNodeIterator(content, NodeFilter.SHOW_TEXT, textFilter);
// Advance to the next sibling or descend to node's children nodes
var node = iterator.nextNode();
// While there is a node...
while (node) {
// ...Go on to it...rinse, lather, and repeat
node = iterator.nextNode();
}
}
findText();
.mark {
color: red;
}
<div>
<div>
RandomText1
<div>
RandomText2
</div>
</div>
</div>
<div>
<div>
<div>
<div>
<div>
<div class='mark'>
6 Deep!
</div>
</div>
</div>
</div>
</div>
<div>
RandomText1
<div>
RandomText2
</div>
</div>
</div>
<div>
<div>
RandomText1
<div>
RandomText2
</div>
</div>
</div>
<div>
<div>
RandomText1
<div>
RandomText2
</div>
</div>
</div>
<div>
<div>
RandomText1
<div>
RandomText2
</div>
</div>
</div>
Upvotes: 3
Reputation: 1280
You don't need to parse each element to find text nodes, you can just recursively traverse childNodes
property of an element
var newText = 'hello world';
function replaceTextNodes(node) {
node.childNodes.forEach(function(el) {
if (el.nodeType === 3) { // If this is a text node, replace the text
if (el.nodeValue.trim() !== "") { // Ignore this node it it an empty text node
el.nodeValue = newText;
}
} else { // Else recurse on this node
replaceTextNodes(el);
}
});
}
var onClick = replaceTextNodes.bind(null, document.querySelector('#container'));
document.querySelector('#replace').addEventListener('click', onClick);
<div id='container'>
<div>
RandomText1
<div>
RandomText2
<ul>
<li>RandomText3</li>
</ul>
</div>
</div>
</div>
<button id="replace">Replace</button>
Upvotes: 5
Reputation: 1434
Loop over your HTML than find nodeValue like this:
document.querySelectorAll('div').forEach(function(o,i){
console.log(o.firstChild && o.firstChild.nodeValue);
})
https://jsfiddle.net/q7ewbswx/
Upvotes: 1
Reputation: 92854
Use TreeWalker object as the most fast tool for DOM traversal.
A TreeWalker can be created using the Document.createTreeWalker() method.
function replaceAllText(newText) {
var walker = document.createTreeWalker(
document.body, // root node
NodeFilter.SHOW_TEXT, // filtering only text nodes
null,
false
);
while (walker.nextNode()) {
if (walker.currentNode.nodeValue.trim()) // if it's not empty(whitespaced) node
walker.currentNode.nodeValue = newText;
}
}
replaceAllText("helloWorld");
<div>
<div>
RandomText1
<div>
RandomText2
</div>
</div>
</div>
https://developer.mozilla.org/en-US/docs/Web/API/Document/createTreeWalker
Performance test demonstration
Upvotes: 4
Reputation: 537
DOM searching done by the browser is very fast, and it optimized also. So, I would suggest to add some common class on the DOM elements which need to be changed and then manipulate them using that class identifier.
Also,
FYI, document.getElementById()
works on DFS and is pretty efficient.
Upvotes: 0