I'm working on a userscript that will make lots of buttons, and I can't seem to give them all an unique function.
I already tried
downArrow.onclick = function (){downVote(id, username)};<br>
and
downArrow.onclick = "downVote(\"" + id + "\", \"" + username + "\")";
But they don't work. Then I read somewhere that only the following works:
downArrow.addEventListener('click', downVote(id, username), false);
This causes that all the buttons will only downvote the last ID and username of the iteration.
I want them all to have unique onclick functions.
Entire for loop:
var targetPosts = document.getElementsByClassName("thing message");
for (var i=0;i<targetPosts.length;i++)
{
try
{
id = targetPosts[i].getAttribute("data-fullname");
username = targetPosts[i].childNodes[4].childNodes[1].childNodes[0].childNodes[1].childNodes[1].childNodes[0].innerHTML;
var upArrow=document.createElement("DIV");
upArrow.className = "arrowUp";
upArrow.id = id + "up";
upArrow.addEventListener('click', function(){ upVote(id, username)} , false);
var downArrow=document.createElement("DIV");
downArrow.className = "arrowDown";
downArrow.id = id + "down";
downArrow.addEventListener('click', function(){ downVote(id, username)} , false
targetPosts[i].childNodes[3].appendChild(upArrow);
targetPosts[i].childNodes[3].appendChild(downArrow);
}
catch(err){}
}
You actually can attach event listeners in a for loop # As you can see from this example, an event listener is successfully attached to each button, and the console is logged each time one of them is clicked. Problems emerge when you try to use your i counter variable within the event callback.
Summary: addEventListener can add multiple events, whereas with onclick this cannot be done. onclick can be added as an HTML attribute, whereas an addEventListener can only be added within <script> elements.
The addEventListener() method allows you to add event listeners on any HTML DOM object such as HTML elements, the HTML document, the window object, or other objects that support events, like the xmlHttpRequest object.
Using the once option We can pass an object as an argument to the addEventListener method and specify that the event is only handled once. This is achieved by passing the property once to the object. If we set once to true, the event will only be fired once.
bind was invented for exactly such a case :
upArrow.addEventListener('click', upVote.bind(upArrow, id, username), false);
should do the job.
Since JavaScript has no block scope (will come with ES6) try the following:
downArrow.addEventListener('click', function(uid, uname) {
return function() {
downVote(uid, uname);
};
}(id, username), false);
When invoking the anonymous function (happens immediately) you capture the current state of id
and username
and use it when the inner function is invoked (happens when the user clicks the button).
In ES6 you can use let id = ...
to define a variable with block scope and your posted code should work fine.
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