最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Passing parameters on event listeners with loops - Stack Overflow

programmeradmin3浏览0评论

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 badges
Add a comment  | 

4 Answers 4

Reset to default 14

JavaScript 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.

发布评论

评论列表(0)

  1. 暂无评论