Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

for...in loop not looping through all properties?

When I load my page, a nodeList gets created, and it looks like this:

[text, h4, text, span, br, input, br, span, br, input, br, span, br, input, br, span, br, input, br]

I created a simple for loop that loops through all these elements and deletes each one of them from the DOM. (all the elements are in a <section>)

Here's the loop:

        for(element in videoTitlesElement.childNodes){
            if(!isNaN(element)){
                videoTitlesElement.removeChild(
                        videoTitlesElement.childNodes[element]);
            }
        }

But, by the end of the loop, the nodeList looks like this:

[h4, span, input, span, input, span, input, span, input]

not all elements got removed. Why?

Thanks.

like image 723
bool3max Avatar asked Nov 30 '22 17:11

bool3max


2 Answers

Two things. First, don't use for ... in when you're iterating through numeric indexes; use a plain for loop. Then you won't need that isNaN() check, and it's generally safer.

The second problem is that when you remove a child, you change the length of the list. If you remove child 0, then the child that used to be child 1 becomes child 0. Thus, what you really want is a simple while loop:

while (videoTitlesElement.childNodes.length)
  videoTitlesElement.removeChild(videoTitlesElement.childNodes[0]);

or, simpler:

while (videoTitlesElement.firstChild)
  videoTitlesElement.removeChild(videoTitlesElement.firstChild);

I should also note (assuming you're working with an HTML DOM) that it's easier to clear out all the child nodes of an element by simply blasting it via .innerHTML:

videoTitlesElement.innerHTML = "";
like image 83
Pointy Avatar answered Dec 04 '22 13:12

Pointy


The list being iterated over (videoTitlesElement.childNodes) is being mutated during iteration. Try iterating over a copy of the original list:

var children = [].slice.call(videoTitlesElement.childNodes);

for(element in children){
    if(!isNaN(element)){
         videoTitlesElement.removeChild(videoTitlesElement.childNodes[element]);
    }
}
like image 32
rjz Avatar answered Dec 04 '22 13:12

rjz