while mdn loop for ejemplos condicion ciclo bucle array javascript for-loop addeventlistener

javascript - mdn - addEventListener usando for loop y passing values



mdn for loop (5)

Cierres! :RE

Este código fijo funciona según lo previsto:

for (var i = 0; i < elem.length; i += 2) { (function () { var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function() { makeItHappen(boxa,boxb); }, false); elem[k].addEventListener("click", function() { makeItHappen(boxb,boxa); }, false); }()); // immediate invocation }

¿Por qué esto lo arregla?

for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); }

Es en realidad un JavaScript no estricto. Se interpreta de esta manera:

var i, k, boxa, boxb; for(i=0; i < elem.length; i+=2){ k = i + 1; boxa = elem[i].parentNode.id; boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); }

Debido a la elevación variable , las declaraciones de var se mueven a la parte superior del alcance. Como JavaScript no tiene alcance de bloque ( for , if , while , etc.) se mueven a la parte superior de la función. Actualización: a partir de ES6 puede usar let para obtener las variables de ámbito de bloque.

Cuando su código se ejecuta, sucede lo siguiente: en el ciclo for agrega las devoluciones de llamada y asigna un boxa , pero su valor se sobrescribe en la siguiente iteración. Cuando el evento click boxa la devolución de llamada se ejecuta y el valor de boxa es siempre el último elemento en la lista.

Utilizando un cierre (cerrando los valores de boxa , boxa , etc.), vincula el valor al alcance del manejador de clics.

Las herramientas de análisis de código como JSLint o JSHint podrán detectar códigos sospechosos como este. Si está escribiendo mucho código, vale la pena tomarse el tiempo para aprender a usar estas herramientas. Algunos IDEs los tienen incorporados.

Esta pregunta ya tiene una respuesta aquí:

Estoy tratando de agregar un detector de eventos a múltiples objetos usando un bucle for, pero terminé con todos los oyentes apuntando al mismo objeto -> el último.

Si agrego los oyentes manualmente definiendo boxa y boxb para cada instancia, funciona. Supongo que es el addEvent for-loop que no funciona de la manera que esperaba. Tal vez uso el enfoque equivocado por completo.

Ejemplo usando 4 de la clase = "contenedor" El disparador en el contenedor 4 funciona de la manera en que se supone que debe hacerlo. Dispara en el contenedor 1,2,3 evento de disparo en el contenedor 4, pero solo si el activador ya se ha activado.

Función para ejecutar al hacer clic:

function makeItHappen(elem, elem2){ var el = document.getElementById(elem); el.style.transform = "flip it"; var el2 = document.getElementById(elem2); el2.style.transform = "flip it"; }

Función de carga automática para agregar los oyentes:

function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); } }

Código HTML

<div class="container"> <div class="one" id="box1"> <p class="triggerClass">some text</p> </div> <div class="two" id="box2"> <p class="triggerClass">some text</p> </div> </div> <div class="container"> <div class="one" id="box3"> <p class="triggerClass">some text</p> </div> <div class="two" id="box4"> <p class="triggerClass">some text</p> </div> </div>


Es a causa de cierres.

Mira esto: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Creating_closures_in_loops_A_common_mistake

El código de muestra y su código son esencialmente iguales, es un error común para aquellos que no conocen el "cierre".

Para simplificar, cuando creas una función de controlador dentro de addEvents() , no solo accede a la variable i desde el entorno de addEvents() , sino que también "recuerda" a i .

Y como su manejador "recuerda" i , la variable i no desaparecerá después de que se haya ejecutado addEvents() .

Entonces, cuando se llama al controlador, usará el i pero la variable i es ahora, después del bucle for, 3.


Puede usar la función de enlace. No necesita usar cierres. Vea a continuación:

Antes :

function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false); elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false); } }

Después :

function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; elem[i].addEventListener("click", makeItHappen.bind(this, boxa, boxb), false); elem[k].addEventListener("click", makeItHappen.bind(this, boxa, boxb), false); } }


También tuve este problema hace un tiempo. Lo resolví usando una función de "agregar" fuera del ciclo, para asignar eventos, y funcionó perfectamente.

Tu script debería verse así.

function addEvents(){ var elem = document.getElementsByClassName("triggerClass"); for(var i=0; i < elem.length; i+=2){ var k = i + 1; var boxa = elem[i].parentNode.id; var boxb = elem[k].parentNode.id; //- edit ---------------------------| adds(boxa, boxb); } } //- adds function ----| function adds(obj1, obj2){ obj1.addEventListener("click", function(){makeItHappen(obj1, obj2);}, false); obj2.addEventListener("click", function(){makeItHappen(obj1, obj2);}, false); } //- end edit -----------------------| function makeItHappen(elem, elem2){ var el = document.getElementById(elem); el.style.transform = "flip it"; var el2 = document.getElementById(elem2); el2.style.transform = "flip it"; }


Usted enfrenta el problema de alcance / cierre como function(){makeItHappen(boxa,boxb);} referencias de boxa y boxb, entonces siempre el último elemento (s).

Para resolver el problema:

function makeItHappenDelegate(a, b) { return function(){ makeItHappen(a, b) } } // ... elem[i].addEventListener("click", makeItHappenDelegate(boxa,boxb), false);