0

i'm looping through an array of 3 buttons inside the for loop i have attached event Listener to each button i'm trying to console.log the button i'm currently looping through but it returns undefined.

let buttons = document.getElementsByClassName('btn');

for (i = 0; i < buttons.length; i++) {
  buttons[i].addEventListener('click', function() {
    console.log(buttons[i]);
    // returns undefined
  })
}
<button class='btn'>a</button>
<button class='btn'>b</button>
<button class='btn'>c</button>
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
AfaqQazi
  • 21
  • 5
  • 2
    By the time your handler is called, `i` is set to `buttons.length`. Using `for (let i...` is the easiest solution. – Ruan Mendes May 07 '19 at 13:21

1 Answers1

1

You can use closure to achieve it.

let buttons = document.getElementsByClassName('btn');

for (let i = 0, ln = buttons.length; i < ln; i++) {
  (function(index) {
    buttons[index].addEventListener('click' , function() {
            console.log(buttons[index]);
            // returns undefined
    })
  })(i)
}
<button class='btn'>a</button>
<button class='btn'>b</button>
<button class='btn'>c</button>

    
Radonirina Maminiaina
  • 6,958
  • 4
  • 33
  • 60
  • 1
    Using `let` is the simplest way to create scoped variables. See my comment. – Ruan Mendes May 07 '19 at 13:21
  • could you please explain why we had to create an i variable and doing it all inside a function ? – AfaqQazi May 07 '19 at 13:23
  • 1
    @AfaqQazi Because by the time your callback is executed, `i` will have been incremented past the end of `buttons.length`. The duplicate question explains this in detail. – Dave Newton May 07 '19 at 13:23
  • @AfaqQazi, I changed a bit my post. You can create a variable and assign that var a value of the current `i` or passing i as a params of the closure function. – Radonirina Maminiaina May 07 '19 at 13:25
  • 3
    This would make total sense if you was trying to keep with `ES5`, but your first line is a `let`, so that's broke that rule. And currently you are creating a global variable called `i`, yes the OP did this too, but if you can use let, the functional scoping is overkill. – Keith May 07 '19 at 13:26
  • 2
    Actually, the best thing would have been not to answer the question at all (delete) since it was pretty clear this had been asked before. If OP has a specific concern after reading the linked question, they should post that question. This is why gave a quick summary as a comment, not an answer. – Ruan Mendes May 07 '19 at 13:27
  • @JuanMendes, I post my answer the same time as it was marked dup. – Radonirina Maminiaina May 07 '19 at 13:28
  • @RadonirinaMaminiaina But I'm sure you knew this had been asked before. This is JS interview 101. – Ruan Mendes May 07 '19 at 13:29