The javascript loop only applies to any other element

I have the following javascript below after i finished the ajax request

all my images have name = "pic"

<script type="text/javascript">
 function done() {
     var e = document.getElementsByName("pic");
     alert(e.length);
     for (var i = 0; i < e.length; i++) {
         cvi_instant.add(e[i], { shadow: 75, shade: 10 });
     }
 }

      

My goal is to apply an image border around this library:

http://www.netzgesta.de/instant/

the problem is that for some reason this works, but it only seems to be applicable to all other images and not all. any hint why the code above will skip every other element?

EDIT: I added a warning in the loop and it correctly goes 0, 1,2,3,4,5,6 ..

     for (var i = 0; i < e.length; i++)
     {
         alert(i);
         cvi_instant.add(e[i], { shadow: 75, shade: 10 });
     }

      

+2


source to share


4 answers


it only seems to apply to any other picture and not to all

This is a classic sign of destructive iteration.

Consider what happens if, as I assume, the function cvi_instant.add

replaces the named element with pic

some other element or elements.

getElementsByName

returns' live NodeList: it is updated every time you make changes to the DOM. So if it had five elements before, after your call it cvi_instant.add

now only contains four: the first node is gone and nodes 1-4 have moved to position 0-3.

You are now traversing the loop again. i++

so we are looking at item 1. But item 1 is now originally item 2! We skipped the original item 1 and we will continue to skip any other item until we reach the end (now one and a half times) of the list.

Changing the list at the same time as iterating causes this problem. If the process inside the iteration actually adds items to the list, you might even end up with an infinite loop!



A quick fix is ​​to repeat the loop backwards. Now you make the last element first, leaving all other elements in their original positions and not causing gaps:

 var e= document.getElementsByName("pic");
 for (var i= e.length; i-->0;) {
     cvi_instant.add(e[i], { shadow: 75, shade: 10 });
 }

      

Another simple solution, if you know that you will always remove an item from the list for every call:

 var e= document.getElementsByName("pic");
 while (e.length>0) {
     cvi_instant.add(e[0], { shadow: 75, shade: 10 });
 }

      

The most general solution is needed when the body of the loop can do something in the list, for example, insert new named elements pic

at the beginning of the document, or remove other elements from the middle. It's a little slower, but it's always safe to make a static copy of the list to work from:

 function Array_fromList(l) {
     var a= [];
     for (var i= 0; i<l.length; i++)
         a.push(l[i]);
     return a;
 }

 var e= Array_fromList(document.getElementsByName("pic"));
 for (var i= 0; i<e.length; i++) {
     cvi_instant.add(e[i], { shadow: 75, shade: 10 });
 }

      

+7


source


I am guessing that cvi_instant.add () is doing some increment or iteration over the values ​​passed to it. Try doing this instead - it's easier and I believe it will fix your problem:



function done() {
  var e = document.getElementsByName('pic');
  for (pic in e) { cvs_instant.add(pic, { shadow: 75, shade: 10 }); }
}

      

+1


source


Hi I faced the same problem. My script was skipping all other element. I finally solved it by simply changing the variable name from i to k in my loop. I am assuming that the variable i is used by getElementsByTagName internally to keep track of where it lives by the nodelist and trickle down to the programmers interface. So this is a bug! :-)

+1


source


- EDIT:

Everything I state below seems to be completely wrong . I leave this here as a point for those who think the same :) I tested FF3. I would happily claim to have seen this behavior in IE once, but it may have been years ago (think about it, probably 7 years ago). My memory is probably bad :)

- OLD:

To expand on my wild guess a bit if it turns out to be accurate:

From memory, if you don't declare a variable ("var ...") it will use it somewhere else.

So without testing, this code:

for(var k = 0; k < 2; k++){
    f();
    alert("k: " + k);
}

function f () {
  k++;
}

      

The same behavior should show. I think the TML solution is pretty good, in terms of "defensive coding", my analysis turns out to be correct.

0


source







All Articles