How can I make sure that addEventListener is not ignoring the iteration I var in the for loop?

I am working on a custom script that will make many buttons, and I cannot show them a unique function.

I already tried -

downArrow.onclick = function (){downVote(id, username)};<br> 

and

  downArrow.onclick = "downVote(\"" + id + "\", \"" + username + "\")"; 

But they do not work. Then I read somewhere that only the following works:

  downArrow.addEventListener('click', downVote(id, username), false); 

This causes all buttons to only reduce the last identifier and iteration username.

I want all of them to have unique onclick features.

The whole cycle:

 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){} } 
+6
source share
3 answers

was invented just for this case:

  upArrow.addEventListener('click', upVote.bind(upArrow, id, username), false); 

must do the job.

+4
source

Since JavaScript does not have a block area (will ship with ES6), try the following:

 downArrow.addEventListener('click', function(uid, uname) { return function() { downVote(uid, uname); }; }(id, username), false); 

When you call an anonymous function (happens right away), you fix the current state of id and username and use it when you call the internal function (happens when the user clicks a button).

In ES6, you can use let id = ... to define a variable with a block scope, and your published code should work fine.

+3
source

I'm not sure how you are trying to do this (it would be better to show the loop code), but overall it is not very safe for creating functions in a loop, because you can mistakenly refer to a variable changing inside the loop, so finally you get all functions using the same identifier. The solution for this is to use some helper function:

 var bindClick = function (element, id, username) { element.addEventListener('click', function () { downVote(id, username); }, false); }, i, mybutton; for (i = 0 ; i < amountOfUsers ; ++i) { mybutton = document.getElementById('downvote-handle-' + i); bindClick(mybutton, i, usernames[i]); } 

thus i value is copied (passed by value) and is safe.

this can be done with an anonymous function, the result will be the same (but IMHO less readable):

 for (i = 0 ; i < amountOfUsers ; ++i) { mybutton = document.getElementById('downvote-handle-' + i); (function (element, id, username) { element.addEventListener('click', function () { downVote(id, username); }, false); }(mybutton, i, userames[i])); } 
+3
source

Source: https://habr.com/ru/post/946263/


All Articles