Stacy J
Stacy J

Reputation: 2781

Javascript addEventListener not working as expected

I am looking into some common Javascript programs. The following one adds 4 buttons to the DOM and adds an event listener to each of them:

for(var i =0;i<5;i++){
    var btn = document.createElement('button');
    btn.appendChild(document.createTextNode('Button' + i));

    //function 1
    (function(i){
     btn.addEventListener('click', function(){console.log(i)});
     })(i);

    //function 2 commented
    /*btn.addEventListener('click', (function(i){
     return function(){
     console.log(i);
     }
     })(i));*/
    
    document.body.appendChild(btn);
}

both function 1 and function 2 add event listener to the buttons and work perfectly. I want to know, why the following code does not :-

for(var i =0;i<5;i++){
    var btn = document.createElement('button');
    btn.appendChild(document.createTextNode('Button' + i));

    btn.addEventListener('click', function(){
        console.log('Clicked' + i);
    });
    document.body.appendChild(btn);
}

This code just logs 5 for every button on click. Why is that, I do not understand why it simply does not hold the value for i for each loop?

Upvotes: 3

Views: 1272

Answers (2)

brk
brk

Reputation: 50291

When addEventListener is added to an eventTarget while it is processing the forloop, it does not trigger the listener.

It is triggered later stage, and at that point the for-loop has finished it's execution and updated the value of i.

When you are creating a function inside the for-loop it is creating a closure and binding the value of i

Upvotes: 1

Gerardo Furtado
Gerardo Furtado

Reputation: 102174

Javascript has no block scope if you use var. So, using exactly your code, you can have the "expected result" replacing var for let:

for(let i =0;i<5;i++){
    var btn = document.createElement('button');
    btn.appendChild(document.createTextNode('Button' + i));

    btn.addEventListener('click', function(){
        console.log('Clicked' + i);
    });
    document.body.appendChild(btn);
}

Upvotes: 2

Related Questions