Removing HTML Element children with JavaScript

Just a quick fyi, but if you are doing work in JavaScript and need to dynamically remove all of the childNodes from a DOM element, make sure to do it with a while loop, and not a for loop. For example, this is bad:

[code]function removeChildrenFromNode(node) { if(node !== undefined && node !=== null) { return; } var len = node.childNodes.length; for(var i = 0; i < len; i++) { node.removeChild(node.childNodes[i]); } }[/code] Since, as soon as you remove one child, the length of node.childNodes is 1 smaller, and you will eventually access an index that does not exist (and get a JavaScript error / exception). The correct way to do this is with a while loop with node.hasChildNodes, like so: [code]function removeChildrenFromNode(node) { if(node !== undefined && node !=== null) { return; } var len = node.childNodes.length; while (node.hasChildNodes()) { node.removeChild(node.firstChild); } }[/code] I just spent quite a bit of time debugging this. In fact, I am pretty sure that this is why the Macromedia News Firefox extension does not currently work well in Firefox 1.5. The odd thing is that this was not an issue prior to Firefox 1.5 (at least not in the Firefox extension). Anyways, just a little heads up of something to watch out for. Thanks to everyone on the Firefox development forums for helping me track this down.

Related Entries

Comments

  1. January 24, 2006 1:11 PM
    yeah, i ran into a similar issue: http://www.visible-form.com/blog/000178.html . Of cours, as someone pointed out in the comments to that post, since you are dealing with a tree structure, a better way would probably be to keep track of the highest removable element in the tree and remove that.
  2. Tangent
    January 24, 2006 1:44 PM
    Using reversed FOR loop is another solution to this problem, where you would write it as for (var i = len - 1; i >= 0; i++)
  3. January 24, 2006 1:57 PM
    Mike, Since the node.hasChildNodes() will always do an evaluation, you can also always do a decremental for() loop. for( var i=len; i > -1; i-- ){ node.removeChild(node.childNodes[i]); } This should be a little more efficient since you're not always doing an evaluation. However, if you have any asynchronous events going on that could be adding to the DOM, the node.hasChildNodes() method would be sure to get all the elements.
  4. Michel
    January 25, 2006 5:37 AM
    I wonder whether the most effective solution would not be : for(var i = 0; i
  5. mike chambers
    January 25, 2006 9:25 AM
    >Since the node.hasChildNodes() will always do an evaluation, you can also always do a decremental for() loop. one minor correction. It should be len - 1 like so: [code]for( var i=len - 1; i > -1; i-- ){ node.removeChild(node.childNodes[i]); }[/code] (this is how i fixed the firefox extension). mike chambers mesh@adobe.com
  6. mike chambers
    January 25, 2006 9:27 AM
    >I wonder whether the most effective solution would not be : Well, the issue is the use of len, since as soon as you remove something, len is not longer valid. mike chambers mesh@adobe.com
  7. January 25, 2006 12:19 PM
    What about: while(node.firstChild) node.removeChild(node.firstChild); This removes the need to call `hasChildNodes()` every time nor do you have to keep referencing the `childNodes` collection (which is a live collection, so takes up some resources).
  8. February 14, 2006 11:33 AM
    Thanks for the code. I ended up with this function: function removeChildrenRecursively(node) { if (!node) return; while (node.hasChildNodes()) { removeChildrenRecursively(node.firstChild); node.removeChild(node.firstChild); } }
  9. May 30, 2006 9:28 AM
    There is a simpler way to remove all children from a node (named parent here): while ( parent.hasChildNodes() ) { parent.removeChild(parent.firstChild); } and you really don't need to recursively remove the children : removing the parent is sufficient.
  10. Chris L
    June 2, 2006 8:34 AM
    Thanks for the great tips, this was bugging me for the last hour or so. Deleting the parent is usually easier, but not always the best solution.
  11. June 8, 2006 3:13 AM
    Thanks - this saved me some agony!
  12. Gus
    June 21, 2006 4:43 PM
    Hi Mike, Thanks for the post. I think you have a logic error in the beginning of your function. You want to return if then node is either null or undefined, and not exit if node neither undefined or null. I think you want this: if(node == undefined || node == null) return; ...though it looks like Mark Wubben's answer is the best.
  13. alternate
    July 4, 2006 3:35 PM
    What if we do node.innerHTML = ""; Would it remove all the child nodes?
  14. jk
    August 10, 2006 3:16 PM
    This is much easier: function removeChildrenFromNode(node) { if(node !== undefined && node !=== null) { return; } var nodes = node.childNodes; for(var i = 0; i
  15. Rui Nunes
    August 22, 2006 1:49 AM
    What about just doing this to clear node childs: myNode.innerText='';
  16. Netrunner
    September 13, 2006 4:49 AM
    Rui Nunes got it! Thank you!
  17. Kari Chase
    September 29, 2006 7:50 AM
    I was successfully able to delete nodes with the removeChild/ while loop as you suggested. However, in my case I am adding/removing tr elements as you expand/collapse a tree structure. In firefox it is working perfectly, in IE after items are removed there seems to be blank white space added in there place which pushes all rows below down and looks awkward. Any ideas why IE is doing this? thanks
  18. Andrew
    October 23, 2006 4:35 PM
    If you wanted to check what you are deleting you could use a for-in loop: for(key in parentNode.childNodes){ if(parentNode.childNodes[key].nodeName == 'IMG'){ parentNode.removeChild(parentNode.childNodes[key]); } }
  19. December 20, 2006 9:11 AM
    Many thanks for this Mike, worked a treat. Des

Post a comment




Remember Me?

(you may use HTML and Quickcode tags for style)