Reputation: 2517
What is the best way to identify and remove empty elements from the dom WITHOUT jQuery?
If I have code that looks like this:
<div>
<div>
<p></p>
</div>
<div>
<p>Some content</p>
</div>
</div>
What is the best way to get rid of both the empty <p>
and <div>
?
I tried this: https://www.sitepoint.com/removing-useless-nodes-from-the-dom/ but for some reason it cleaned out all of the spaces in my spans.
Upvotes: 2
Views: 5025
Reputation: 130215
I would use TreeWalker to traverse the DOM and find empty nodes.
In the below example, an empty node is considered as a node which has no text anywhere inside it, regardless of tree depth or whitespaces. A node can also be considered empty only if it has no children.
var treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT)
var currentNode = treeWalker.currentNode
var emptyNodes = []
// test if a node has no text, regardless of whitespaces
var isNodeEmpty = node => !node.textContent.trim()
// find all empty nodes
while(currentNode) {
isNodeEmpty(currentNode) && emptyNodes.push(currentNode)
currentNode = treeWalker.nextNode()
}
// remove found empty nodes
emptyNodes.forEach(node => node.parentNode.removeChild(node))
// print DOM
console.log(document.body.firstElementChild.outerHTML)
<div>
<div>
<p></p>
</div>
<div>
<p>Some content <a></a></p>
</div>
</div>
Note that while traversing the DOM using TreeWalker, nodes should not be removed because it will mess up the "live" DOM iteration.
Upvotes: 3
Reputation: 1
You can use :only-child
pseudo class to select elements which are the only child of a parent element, remove the node, then check if the parent node has .children
, if not remove the parent node
let nodes = document.querySelector("div")
.querySelectorAll(":only-child");
nodes.forEach(node => {
if (!node.childNodes.length) {
let parent = node.parentNode;
node.parentNode.removeChild(node);
if (!parent.children.length) {
parent.parentNode.removeChild(parent)
}
}
});
console.log(document.querySelector("div").innerHTML);
<div>
<div>
<p></p>
</div>
<div>
<p>Some content</p>
</div>
</div>
Upvotes: 0
Reputation: 1092
You could use querySelectorAll
to get all of the elements of a type and then determine if that element has innerText
.
var wrapper = document.querySelector('.content-wrapper');
var ps = wrapper.querySelectorAll('p');
for (var p = 0; p < ps.length; p++) {
if (ps[p].innerText === '') {
wrapper.removeChild(ps[p].parentNode);
}
}
var divs = wrapper.querySelectorAll('div');
for (var d = 0; d < divs.length; d++) {
if (divs[d].querySelectorAll('p').length === 0) {
wrapper.removeChild(divs[d]);
}
}
.content-wrapper {
height: 100%;
width: 100%;
}
.content-wrapper>div {
width: 100%;
height: 100px;
color: #fff;
}
<div class="content-wrapper">
<div style="background-color: red;">
</div>
<div style="background-color: green;">
<p>
</p>
</div>
<div style="background-color: blue;">
<p>
Text!
</p>
</div>
</div>
Upvotes: 0
Reputation: 12880
You could try to build a recursive function checking if an element's innerHTML
is empty to remove them all :
function recursiveCleaner(el){
if (el.childNodes.length > 0) {
for(var i=0;i<el.childNodes.length;i++){
recursiveCleaner(el.children[i]);
}
for(var i=0;i<el.childNodes.length;i++){
if(el.children[i].innerHTML === "") el.removeChild(el.children[i]);
}
}
}
Upvotes: 0