Mike Chambers

code = joy

Removing HTML Element children with JavaScript

with 26 comments

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:

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]);
   }
}

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:

function removeChildrenFromNode(node)
{
   if(node !== undefined &&
        node !=== null)
   {
      return;
   }

   var len = node.childNodes.length;

	while (node.hasChildNodes())
	{
	  node.removeChild(node.firstChild);
	}
}

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.

Written by mikechambers

January 24th, 2006 at 12:00 pm

Posted in General

26 Responses to 'Removing HTML Element children with JavaScript'

Subscribe to comments with RSS

  1. 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.

    flashape

    24 Jan 06 at 1:11 pm

  2. Using reversed FOR loop is another solution to this problem, where you would write it as for (var i = len – 1; i >= 0; i++)

    Tangent

    24 Jan 06 at 1:44 pm

  3. 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. I wonder whether the most effective solution would not be :
    for(var i = 0; i I wonder whether the most effective solution would not be :
    for(var i = 0; i < len; i++)
    {
    node.removeChild(node.childNodes[0]);
    }
    or may be :
    for(var i = 0; i < len; i++)
    {
    node.removeChild(node.firstChild);
    }

    Michel

    25 Jan 06 at 5:37 am

  5. >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

    mike chambers

    25 Jan 06 at 9:25 am

  6. >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

    mike chambers

    25 Jan 06 at 9:27 am

  7. 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).

    Mark Wubben

    25 Jan 06 at 12:19 pm

  8. 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);
    }
    }

    mwarden

    14 Feb 06 at 11:33 am

  9. 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. 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.

    Chris L

    2 Jun 06 at 8:34 am

  11. Thanks – this saved me some agony!

    jvvw

    8 Jun 06 at 3:13 am

  12. 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.

    Gus

    21 Jun 06 at 4:43 pm

  13. What if we do

    node.innerHTML = “”;

    Would it remove all the child nodes?

    alternate

    4 Jul 06 at 3:35 pm

  14. This is much easier:

    function removeChildrenFromNode(node)
    {
    if(node !== undefined &&
    node !=== null)
    {
    return;
    }

    var nodes = node.childNodes;

    for(var i = 0; i This is much easier:

    function removeChildrenFromNode(node)
    {
    if(node !== undefined &&
    node !=== null)
    {
    return;
    }

    var nodes = node.childNodes;

    for(var i = 0; i < nodes.length; i++)
    {
    node.removeChild(nodes[i]);
    }
    }

    This way all your nodes are copied to var nodes, so when you delete you don’t get out of reference and you can still use regular forwards for loop.

    jk

    10 Aug 06 at 3:16 pm

  15. What about just doing this to clear node childs:
    myNode.innerText=”;

    Rui Nunes

    22 Aug 06 at 1:49 am

  16. Rui Nunes got it!
    Thank you!

    Netrunner

    13 Sep 06 at 4:49 am

  17. 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

    Kari Chase

    29 Sep 06 at 7:50 am

  18. 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]);
    }
    }

    Andrew

    23 Oct 06 at 4:35 pm

  19. Many thanks for this Mike, worked a treat.
    Des

    Des Traynor

    20 Dec 06 at 9:11 am

  20. people are stranger

    emurhfkq

    21 Jun 07 at 6:41 pm

  21. Thanks! This was a big help!

    jerrygarciuh

    26 Jun 07 at 5:09 am

  22. Just wondering, for this part …
    if(node !== undefined && node !=== null)

    Dont you want to return nothing if the values are null or undefined, so only proceed if have a valid node? aka
    if(node == undefined && node == null)
    return null;
    //otherwise do while loop

    Anyway in the orig code, ‘!===’ a javascript equality operator?
    I know ‘!==’ is strict equality operator, is ‘!===’ a mistake? i guess doesnt matter if that line should be replaced.

    Arian

    2 Nov 07 at 5:35 am

  23. DOM should work on all: IE, Firefox and Opera. I am using the one!

    Bimal

    18 Feb 08 at 1:33 am

  24. I just thought you might want to know that I just got an error with the initial testing on the node variable in IE7 and Firefox, but it worked when I removed the following section:

    if(node !== undefined && node !=== null) {
    return;

    Evan Bowling

    14 Mar 08 at 9:34 am

  25. I am doing this:

    var removeChildren = function (node) {
    while (node.hasChildNodes()) {
    node.removeChild(node.firstChild);
    }
    };

    and firefox keeps telling me:

    node.hasChildNodes is not a function

    Nick

    22 Jul 08 at 7:20 am

  26. Hi,
    I am currently tracking memory leak bugs in Internet Explorer for a product. I wanted to point out that using innerHTML=”" can cause memory leaks and removing children can cause memory leaks if any child elements have event handlers. Googling these terms should yield enough results to get you started. Beware of methods that do not take this into account.

    D3c1m4L

    23 Sep 08 at 4:49 pm

Leave a Reply