Pasar parameters en los detectores de events con loops

Solo una pregunta rápida, ¿alguien puede decirme por qué esto no funciona y cómo solucionarlo? Básicamente se trata de tomar un grupo de filas de tablas en HTML y adjuntar events de clics dinámicamente a ellas.

for (var a=index; a<rows.length; a++) { tr = rows[a]; tr.onclick = function() { DropDownManager.onItemClick(tr, a); }; tr.observe("click", function() { DropDownManager.onItemClick(tr, a); }); } 

El problema con este código es que los valores pasados ​​a DropDownManager.onItemClick son siempre los últimos elementos en el ciclo, esto no es lo que quiero después, ya que quería que fuera el valor actual en esa etapa del ciclo. ¡Me doy count de que me estoy perdiendo algo bastante simple, pero no puedo por la vida de mí resolverlo!

JavaScript no tiene ámbito de bloque, por lo que, por ejemplo, los loops no crean un nuevo ámbito. Puede crear uno usando una function:

 for (var a=index; a<rows.length; a++) { (function(a) { tr = rows[a]; tr.onclick = function() { DropDownManager.onItemClick(this, a); }; tr.observe("click", function() { DropDownManager.onItemClick(this, a); }); }(a)); } 

Dependiendo de qué rows y tr son, es posible que ni siquiera necesite el índice de bucle. Tal vez puedas get el índice de elementos dentro del controller de events de otra manera. Por ejemplo, si tr es HTMLTableRowElement [MDN] , puede get su position entre las otras filas a través de this.rowIndex .

Por cierto. ¿Por qué vinculas el mismo controller de events dos veces?

Además de almacenar los attributes en el object DOM en el bucle, también puede usar cierres de function para "congelar" una copy de las variables en el bucle para una llamada de function en particular. Puedes hacerlo así:

 for (var a=index; a<rows.length; a++) { tr = rows[a]; tr.onclick = function(tr, a) { return(function() { DropDownManager.onItemClick(tr, a); }); }(tr,a); } 

Lo que hace es decir asignar clonar los resultados de ejecutar una llamada de function anónima que toma dos variables como parameters (llamados tr y a) y pasa los valores actuales de tr y a como parameters (este paso de los valores actuales " congela "los valores actuales de esas variables dentro de este cierre de function.

El resultado de ejecutar esa llamada de function es en sí mismo otra function anónima. Debido a que esta function anónima interna ahora está asignada a tr.onclic, crea un cierre de function que mantiene vivo todo el estado que se encuentra actualmente en ese cierre. Ese estado incluye los valores "congelados" de tr y a, pero se mantienen internos solo para el cierre de esta function, por lo que cada vez que pasa crea una nueva function con un nuevo valor "congelado" y "almacenado" de tr y a.

En parte porque soy pedante y en parte porque es posible, aquí se hace lo mismo simplemente.

 Event.on('table_id', 'click', 'tr', function(event, tr) { DropDownManager.onItemClick(tr, rows.indexOf(tr)); }); 

Tenga en count que la tabla que contiene es necesaria para que los events salgan a borbotones, se identifica por su ID, pero también puede pasar el elemento directamente.

 for (var a=index; a<rows.length; a++) { tr = rows[a]; tr.setAttribute('a', a); tr.onclick = function() { DropDownManager.onItemClick(this, this.getAttribute('a')); }; tr.observe("click", function() { DropDownManager.onItemClick(this, this.getAttribute('a')); }); } 

testing de esta manera

Pasará tr porque la variable tr se establece como una última fila.