Remove element nodes in post-order traversal
javascript, jquery
Solution
First build a post-order (aka child first) version of the DOM tree using the following recursive function:
var nodes = [];
function generate()
{
$(this).children().each(generate);
nodes.push(this);
}
generate.call($('body'));
Then, iterate as per normal:
var i = 0;
function loop()
{
$(nodes[i]).remove();
if (++i < nodes.length) {
setTimeout(loop, 1000);
}
}
loop();
Demo
Problem
Say I have the following HTML (condensed): ``` <div><div><div><ul><li>Text</li></ul></div></div></div> <div><div><div><ul><li>Text 2</li></ul></div></div></div> <div><div><div><ul><li>Text 3</li></ul></div></div></div> ``` I want to remove the lowest child elements first, until ultimately removing the parent, then move on to the next parent element and its children. This can be easily accomplished by a simple loop that goes through each child element, removes it, then removes the next child element (i.e. parent of the previous child): ``` var children = $("body").find("*"); var i = children.length; function loop() { $(children[i]).remove(); i--; if (i > -1) { setTimeout(loop, 20); } } loop(); ``` The problem with this, however, is that it removes the child elements from the lowest parent element first. If you were to run this code with my test markup, you could see what I mean. I want to remove the child elements from the top most parent, then work my way down, therefore reversing the order of the above code. I was able to somewhat accomplish this with the following code: ``` var parents = $("body").children(":not(:empty)"); var i = 0; var speed = 1000; function loop() { var children = $(parents[i]).find("*"); var x = children.length; function inside() { $(children[x]).remove(); x--; if (x > -1) { setTimeout(inside, speed); } else if (i < parents.length) { $(parents[i - 1]).remove(); loop(); } else if (i === parents.length) { $(parents[i - 1]).remove(); } } inside(); i++; } loop(); ``` The problem with this code, however, is that it only reverses the order of deleting with respect to the parent element. If there are multiple child elements within a parent, it will still delete them in the default ascending order (bottom to top). My question, therefore, is how can I delete all the elements in descending order, regardless of how many child elements there are, in a much cleaner fashion? There has to be a much better approach than what I attempted. jQuery isn't a requirement either. The reason for the `setTimeout`s is because I need a delay between removing the elements. As usual, I probably overlooked something relatively simple, so bear with me. To reiterate, if the HTML looks like this: ``` <div> <div>Child 1</div> <div>Child 2</div> <div> <div>Child 3</div> <div>Child 4</div> </div> </div> ``` I would want it to be deleted in the following order: - Child 1 - Child 2 - Child 3 - Child 4