When you attach multiple click events to elements such as buttons inside a for loop, the click event will always give us the last index value regardless of what button is pressed.
This is one of the common problems developers face when they start learning JavaScript.
By the end of this article, you will know what causes this issue and some of the ways to fix it.
- Why do I need to know Hoisting?
- Why i variable always get the last index in a loop?
- Variable Scope Issue
- Solution #1: Closure (IIFE)
- Solution #2: Closure Outer Function Returns Inner Function
- Solution #3: Use forEach instead of for
- Solution #4: Use let instead of var
- Bonus: Declare Callback function outside of the loop
Code Snippet That Causes The Problem
As you can see, the HTML page has a div element with an id called buttonsContainer.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="buttonsContainer"></div>
</body>
</html>
This is where I added five buttons dynamically using for loop in the javascript code below.
const buttonsContainer = document.getElementById("buttonsContainer");
for (var i = 0; i < 5; i++) {
const button = document.createElement("button");
button.innerText = i;
button.addEventListener("click", function() {
console.log(i)
})
buttonsContainer.appendChild(button);
}
I also attached a click event to a button element and appended it to the buttonContainer element on each iteration.
If I run this code at this stage, I will get a value of 5 regardless of what button is pressed.
Before understanding what’s happening here… we need to know…what is hoisting.
✅ Recommended
The Complete JavaScript Course 2020: Build Real Projects!
Hoisting
By default, a variable declared with var keyword is function scoped but not block-scoped.
So, any variable declared inside a function, regardless of how deep it is, will be moved to the top and accessible anywhere inside that function.
On the other hand, if a variable is declared outside of a function, it will become a globally scoped variable and we can access it anywhere in the application as it belongs to the window object (browser only).
That behavior is called Hoisting.
Variable i Always Has the Last Index
Let’s see what happens to the code above now.
The i variable declared with var keyword will be automatically moved to the top of the page as it’s not declared inside a function so it becomes a global variable because of hoisting.
So the i variable is clearly not scoped to the for loop but it’s globally scoped and it’s bound to the same variable outside of the callback function on each iteration.
By the time, the for loop reaches the last iteration, the i variable will end up holding the last index value. That’s why the output will always be the last index, in my case, 5.
✅ Recommended
JavaScript Working with Images
i is a Global Variable
I am going to console log i variable outside of the for loop.
} // end of for loop
console.log(i);
You will get 5 in the browser console as soon as the code finishes executing without even clicking any of the buttons.
This proves that the variable i is globally scoped.
Now we know the culprit, which is the i variable declared with the var keyword.
Let’s take a look at a few solutions to fix it.
Top comments (1)
Why you use createElement If anyone don't want to create new element on javascript your method won't be working.