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
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.
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.
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.
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); } }
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 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.
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); });
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With