Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

adding 'click' event listeners in loop [duplicate]

Tags:

Refactoring standard onClick within html tag to listeners ,faced problem with my code:

var td;     for (var t=1;t<8;t++){         td = document.getElementById('td'+t);         if (typeof window.addEventListener==='function'){                 td.addEventListener('click',function(){                     console.log(td);             })}  }   

When td element is clicked on,it's assumed that clicked td with last index from loop,e.g. 7
Looks like ,eventListeners been populated for last element in this loop only.
Loop initialization looks correct.
Why so happened?

Here is live code

like image 596
sergionni Avatar asked Jan 18 '12 11:01

sergionni


People also ask

Can you add the same event listener twice?

If multiple identical EventListeners are registered on the same EventTarget with the same parameters the duplicate instances are discarded. They do not cause the EventListener to be called twice and since they are discarded they do not need to be removed with the removeEventListener method.

Can you add multiple click event listeners?

The addEventListener() methodYou can add many event handlers of the same type to one element, i.e two "click" events. You can add event listeners to any DOM object not only HTML elements. i.e the window object.

How do you add an event listener to multiple elements with the same ID?

Adding event listener to multiple elements To add the event listener to the multiple elements, first we need to access the multiple elements with the same class name or id using document. querySelectorAll() method then we need to loop through each element using the forEach() method and add an event listener to it.


2 Answers

You need to wrap the assignment of the event listener in a closure, something like:

var td; for (var t = 1; t < 8; t++){     td = document.getElementById('td'+t);     if (typeof window.addEventListener === 'function'){         (function (_td) {             td.addEventListener('click', function(){                 console.log(_td);             });         })(td);     } } 
like image 169
jabclab Avatar answered Sep 21 '22 10:09

jabclab


What's happening

The variable td is defined outside of your event handlers, so when you click on a cell you are logging the last value it was set to.

More technically: each event handler function is a closure—a function that references variables from an outer scope.

The general solution

The general solution to this kind of problem is to return the event handler from a wrapper function, passing the variables you want to "fix" as arguments:

td.addEventListener('click', function(wrapTD) {     return function() { console.log(wrapTD); } }(td)); 

The arguments are now bound to the scope of the invoked wrapper function.

Simpler solution: use this

There's an even simpler option, however. In an event handler, this is set to the element on which the handler is defined, so you can just use this instead of td:

td.addEventListener('click', function() {     console.log(this); }); 

Even simpler: no loop!

Finally, you can get rid of the for loop entirely and set a single event handler on the whole table:

var table = document.getElementById('my-table');  table.addEventListener('click', function(e) {     if (e.target.nodeName.toUpperCase() !== "TD") return;      var td = e.target;     console.log(td); }); 

This is a much better solution for larger tables, since you are replacing multiple event handlers with just one. Note that if you wrap your text in another element, you will need to adapt this to check if the target element is a descendant of a td.

like image 36
Jordan Gray Avatar answered Sep 19 '22 10:09

Jordan Gray