Reputation: 14489
I'm trying to remove all child elements from a node but leave the actual text content of the node. I.e. go from this:
<h3>
MY TEXT
<a href='...'>Link</a>
<a href='...'>Link</a>
<select>
<option>Value</option>
<option>Value</option>
</select>
</h3>
to this:
<h3>
MY TEXT
</h3>
I know that there are a million easy ways to do this in jQuery, but it's not an option for this project... I've got to use plain old javascript.
This:
var obj = document.getElementById("myID");
if ( obj.hasChildNodes() ){
while ( obj.childNodes){
obj.removeChild( obj.firstChild );
}
}
obviously results in just <h3></h3>
, and when I tried:
var h3 = content_block.getElementsByTagName('h3')[0];
var h3_children = h3.getElementsByTagName('*');
for(var i=0;i<h3_children.length;i++){
h3_children[i].parentNode.removeChild(h3_children[i]);
}
It gets hung up part way through. I figured it was having trouble removing the options, but altering the for
loop to skip removal unless h3_children[i].parentNode==h3
(i.e. only remove first-level child-elements) stops after removing the first <a>
element.
I'm sure I'm missing something super obvious here, but perhaps it's time to turn to the crowd. How can I remove all child elements but leave the first-level textNodes
alone? And why doesn't the above approach work?
There are a couple of working solutions posted, which is great, but I'm still a little mystified as to why looping through and removing h3.getElementsByTagName('*')
doesn't work. A similar approach(adapted from Blender) likewise does not complete the process of removing child nodes. Any thoughts as to why this would be?
Upvotes: 3
Views: 3891
Reputation: 2484
Well, The thing I used (inspired from the answers here) is somewhat like:
var h3 = document.getElementsByTagName("h3")[0];
Array.protoype.filter.call(h3.childNodes, function(child){
if (child.nodeType != 3) {
h3.removeChild(child);
}
});
Upvotes: 0
Reputation: 10080
var h3=content_block.getElementsByTagName("h3")[0];
for(var i=0;i<h3.childNodes.length;i++)
{
if(h3.childNodes[i].nodeType==3)//TEXT_NODE
{
continue;
}
else
{
h3.removeChild(h3.childNodes[i]);
i--;
}
}
Edit:
Combined the i--
to make it look shorter:
var h3=content_block.getElementsByTagName("h3")[0];
for(var i=0;i<h3.childNodes.length;i++)
{
if(h3.childNodes[i].nodeType==3)//TEXT_NODE
continue;
else
h3.removeChild(h3.childNodes[i--]);
}
Edit #2:
Pointed out by @SomeGuy, make it even shorter:
var h3=content_block.getElementsByTagName("h3")[0];
for(var i=0;i<h3.childNodes.length;i++)
{
if(h3.childNodes[i].nodeType!=3)//not TEXT_NODE
h3.removeChild(h3.childNodes[i--]);
}
The brackets can be removed too, but that would be "less readable" and "confusing", so I keep it there.
Upvotes: 3
Reputation: 77
try this. I am assuming you will keep ant text here.
var h3 = document.getElementsByTagName('h3')[0];
if (h3.hasChildNodes()) {
for (var i = h3.childNodes.length - 1; i >= 0; i--) {
if (h3.childNodes[i].nodeName != "#text")
h3.removeChild(h3.childNodes[i]);
}
}
Hope it will work.
Upvotes: 1
Reputation: 3171
For instance:
var e = obj.firstChild
while (e) {
if (e.nodeType == 3) {
e = e.nextSibling
} else {
var n = e.nextSibling
obj.removeChild(e)
e = n
}
}
Upvotes: 1
Reputation: 3907
You can check properties .nodeType
or .nodeName
for each node.
Text nodes have these properties set to:
.nodeType == 3
.nodeName == '#text'`
Upvotes: 1