Passing parameters for event listeners with loops

Just a quick question, can someone tell me why this is not working and how to fix it? Essentially, it takes a group of table rows in HTML and dynamically attaches click events to them.

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); }); } 

The problem with this code is that the values ​​passed to DropDownManager.onItemClick are always the last elements of the loop, it's not like im after I wanted them to be the current value at this point in the loop. I understand that I missed something very simple, but I can’t let my life work!

+8
javascript html prototypejs events
source share
4 answers

JavaScript does not have a block scope; for example, loops do not create a new scope. You can create it using the 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)); } 

Depending on what rows and tr , you may not even need a loop index. Perhaps you can get the index of the elements inside the event handler differently. For example. if tr is HTMLTableRowElement [MDN] , you can get your position among other lines through this.rowIndex .

Btw. why do you bind the same event handler twice?

+14
source share

Besides storing the attributes of a DOM object in a loop, you can also use function locks to “freeze” a copy of variables in a loop for a particular function call. You can do it as follows:

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

This means that it assigns tr.onclick the results of an anonymous function call, which takes two variables as parameters (named tr and a) and passes the current values ​​of tr and a as parameters (this transmission, the current values ​​“freeze” the current values ​​of these variables inside this function.

The result of this function call is another anonymous function. Since this internal anonymous function is now assigned to tr.onclick, it creates a function closure that retains all the state that is currently in this closure. This state includes the “frozen” values ​​of tr and a, but they remain internal only to close this function, so every time a new function closure is created through the loop with a new “frozen” and “saved” value of tr and a.

+4
source share

Partly because I am pedantic and partly because it is possible, the same thing is done simply.

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

Note that the containing table is necessary for events that may bubble up, it is identified by an identifier, but you can also pass an element directly.

0
source share
 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')); }); } 

try this way.

It will pass tr because the tr variable is set as the last line.

-one
source share

All Articles