Just a quick question, can anyone tell me why this doesnt work and how to fix it? Essentially its taking a group of table rows in HTML and dynamically attaching 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 into DropDownManager.onItemClick are always the last items in the loop, this isn't what im after as i wanted them to be the current value in that stage of the loop. I realize I'm missing something quite simple but cant for the life of me work it out!
Just a quick question, can anyone tell me why this doesnt work and how to fix it? Essentially its taking a group of table rows in HTML and dynamically attaching 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 into DropDownManager.onItemClick are always the last items in the loop, this isn't what im after as i wanted them to be the current value in that stage of the loop. I realize I'm missing something quite simple but cant for the life of me work it out!
Share Improve this question edited Dec 28, 2011 at 15:02 Tom van der Woerdt 30k7 gold badges74 silver badges105 bronze badges asked Aug 6, 2011 at 16:28 Ian HarriganIan Harrigan 8366 silver badges14 bronze badges4 Answers
Reset to default 14JavaScript has no block scope, so e.g. loops don't create a new scope. You can create one by using a 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
are, you might not even need the loop index. Maybe you can get the elements index inside the event handler through another way. E.g. if tr
is a HTMLTableRowElement
[MDN], then you can get its position among the other rows via this.rowIndex
.
Btw. why are you binding the same event handler twice?
Aside from storing the attributes on the DOM object in the loop, you can also use function closures to "freeze" a copy of the variables in the loop for a particular function call. You can do it like this:
for (var a=index; a<rows.length; a++) {
tr = rows[a];
tr.onclick = function(tr, a) {
return(function() {
DropDownManager.onItemClick(tr, a);
});
}(tr,a);
}
What this does is says to assign tr.onclick the results of executing an anonymous function call that takes two variables as parameters (named tr and a) and is passed the current values of tr and a as parameters (this passing of the current values "freezes" the current values of those variables inside this function closure.
The result of executing that function call is itself another anonymous function. Because this internal anonymous function is now assigned to tr.onclick, it creates a function closure that keeps alive all the state that is currently in that closure. That state includes the "frozen" values of tr and a, but they are kept internal to just this function closure so every time through the loop creates a new function closure with a new "frozen" and "stored" value of tr and a.
Partly because I'm pedantic and partly because it's possible, here is the same thing done simply.
Event.on('table_id', 'click', 'tr', function(event, tr) {
DropDownManager.onItemClick(tr, rows.indexOf(tr));
});
Notice the containing table is needed for events to bubble up to, it is identified by it's ID but you could pass the element directly as well.
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 variable tr is set as a last row.