Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite For Loop that is not paying attention to array-length condition

HTML example

    <html>
       <img src="http://img3.wikia.nocookie.net/__cb20130606164012/animalcrossing/images/3/30/Monkey.jpg" width="200px"><br />
       <img src="http://i.telegraph.co.uk/multimedia/archive/02101/monkeys_2101340c.jpg" width="200px"><br />
       <img src="http://www.awallpapersonline.com/wp-content/uploads/2014/03/Baby-monkeys-pictures-5-419x400.jpg" width="200px"><br />
       <p id="sliderImages"><p>
    </html>

And my Javascript looks like

var monkey = document.getElementsByTagName("img");
var paragraph = document.getElementById('thisPar');
paragraph.innerHTML += '<img src="' + monkey[0].src +'" width="200">';

Which works perfectly fine.

HOWEVER WHEN I PUT IT IN A LOOP THAT LOOKS LIKE

var monkey = document.getElementsByTagName("img");
var paragraph = document.getElementById('thisPar');
for(var i = 0; i < monkey.length; i++){
    paragraph.innerHTML += '<img src="' + monkey[i].src +'" width="200">';
}

It prints an infinite loop of all my monkey pictures. I figure by making the condition dependent on the number of elements in the array "monkey" (or the number of img tags on the page), I would be able to print that amount of pictures in the 'thisPar' paragraph id.

Why is this statement creating an endless loop?

like image 787
beckah Avatar asked Apr 23 '14 17:04

beckah


3 Answers

document.getElementsByTagName returns a live HTMLCollection. Since you are adding more img tags, you are extending the collection by one element each cycle through the loop.

If you add a console.log(monkey.length) inside your loop, you'll see the problem.

The best solution would be to do this:

var monkey = document.querySelectorAll("img");

Instead of getElementsByTagName. querySelectorAll will return a static list.

Here's a fiddle that will show you the length of monkey.length on each cycle. I made it a confirm so you can break out by clicking cancel:

http://jsfiddle.net/K266Q/

And here's the fixed version using querySelectorAll:

http://jsfiddle.net/K266Q/1/

Copying the length outside the loop also works, but only so long as the items stay in the same order. Here's why simply copying the length can catch you out:

http://jsfiddle.net/K266Q/2/

Notice because in this case I'm inserting the new image at the beginning instead of the end, I end up copying the same image 3 times.

like image 86
Matt Burland Avatar answered Nov 14 '22 23:11

Matt Burland


When defining the length outside of the For loop, it worked fine.

var LENGTH = img.length;
for(var i=0; i < LENGTH; i++){
    monkeyPara.innerHTML += '<img src="' + img[i].src + '" height="42" width="42">';

}
like image 32
beckah Avatar answered Nov 15 '22 01:11

beckah


Only works if the new img is inserted after the original set of images : define a variable and assign it to your monkey length property outside the loop to make it fixed:

var monkeyLength = monkey.length;
for(var i = 0; i < monkeyLength; i++){
   paragraph.innerHTML += '<img src="' + monkey[i].src +'" width="200">';
}
like image 32
potashin Avatar answered Nov 15 '22 00:11

potashin