0

So I have a simple question, my button onclick events that's created dynamically, only appears to reference the last index. In my for loop, if I used i, I get the error "Uncaught TypeError: Cannot read property 'setAttribute' of undefine". If I put in an index like 5, I will get the correct button. I am sure it's something I'm overlooking and I have referenced other documents out here to no luck.

<html>
<body>
<div id="numbers"></div>

<?php
$read = file('numbers.txt');?>
<script>
var rest = '<?php echo json_encode($read[0]); ?>'
rest = String(rest).replace('"','').replace('"','')
rest = rest.split(',')
console.log(rest)
for(i=0;i<rest.length;i++){
    var btn = document.createElement("BUTTON");
    var t = document.createTextNode(rest[i]);
    btn.id = "but"+String(i);
    btn.setAttribute("style","color:red;font-size:23px");
    btn.appendChild(t);
    document.body.appendChild(btn);
    btn.addEventListener("click", function test(){
        btn[i].setAttribute("style","color:green;font-size:23px");   
            });     
}

</script>

</body>
</html>

***other example

<html>
<body>
<div id="numbers"></div>

<?php
$read = file('numbers.txt');?>
<script>
var rest = '<?php echo json_encode($read[0]); ?>'
rest = String(rest).replace('"','').replace('"','')
rest = rest.split(',')
console.log(rest)
for(i=0;i<rest.length;i++){
    var btn = document.createElement("BUTTON");
    var t = document.createTextNode(rest[i]);
    btn.id = "but"+String(i);
    btn.setAttribute("style","color:red;font-size:23px");
    btn.appendChild(t);
    document.body.appendChild(btn);
    btn.onclick = function test(){
        document.getElementsByTagName('button')[i].setAttribute("style","color:green;font-size:23px");   
            }       
}

</script>

</body>
</html>
Jason Owens
  • 525
  • 2
  • 6
  • 21

1 Answers1

1

a simple fix would be the following

btn.addEventListener("click", function test(){
    this.setAttribute("style","color:green;font-size:23px");   
});   

the issue with the doing something like --

btn.setAttribute("style","color:green;font-size:23px");   

or

document.getElementsByTagName('button')[i].setAttribute("style","color:green;font-size:23px");   

is that on adding event listeners, the functions are not executed immediately, instead they are executed when the user clicks on the button, at which point the loop has finished executing, and both 'i' and 'btn' refer to the last button created.

Thus using 'this' immediately solves the problem.

space_mill
  • 359
  • 2
  • 5
  • I did btn.addEventListener('click', (function (bound_i){ return function() { document.getElementsByTagName('button')[bound_i].setAttribute("style","color:green;font-size:23px"); console.log(bound_i) } })(i)); and that worked, but your way was less code. – Jason Owens Jun 01 '20 at 20:01