JavaScript For Loop Click Event Issues & Solutions Explained
Tags: javascript, programming
Published: 2021-04-06 00:44:40

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.

{% youtube aZbgE3yhC2o %}

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?](https://www.softauthor.com/javascript-for-loop-click-event-issues-solutions/#what-is-hoisting)
- [Why i variable always get the last index in a loop?](https://www.softauthor.com/javascript-for-loop-click-event-issues-solutions/#i-variable-always-get-the-last-index-in-a-loop)
- [Variable Scope Issue](https://www.softauthor.com/javascript-for-loop-click-event-issues-solutions/#variable-scope-issue)
- [Solution #1: Closure (IIFE)](https://www.softauthor.com/javascript-for-loop-click-event-issues-solutions/#what-is-closure-iife)
- [Solution #2: Closure Outer Function Returns Inner Function](https://www.softauthor.com/javascript-for-loop-click-event-issues-solutions/#closure-outer-function-returns-inner-function)
- [Solution #3: Use forEach instead of for](https://www.softauthor.com/javascript-for-loop-click-event-issues-solutions/#use-foreach-instead-of-for)
- [Solution #4: Use let instead of var](https://www.softauthor.com/javascript-for-loop-click-event-issues-solutions/#use-let-instead-of-var)
- [Bonus: Declare Callback function outside of the loop](https://www.softauthor.com/javascript-for-loop-click-event-issues-solutions/#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**.

```HTML
<!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.

```Javascript
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!](https://www.udemy.com/course/the-complete-javascript-course/?ranMID=39197&ranEAID=nsrC6aUWa3g&ranSiteID=nsrC6aUWa3g-VICQ6LkwG.xSRxn.J1E2Jg&LSNPUBID=nsrC6aUWa3g&utm_source=aff-campaign&utm_medium=udemyads)

##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](https://www.softauthor.com/javascript-working-with-images/)

##**i** is a Global Variable

I am going to console log **i** variable outside of the for loop.

```Javascript
} // 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.

[Continue Reading...](https://www.softauthor.com/javascript-for-loop-click-event-issues-solutions/#declare-callback-function-outside-of-the-loop)