I have a page that has a number of divs on it and I am writing a function that loops over all of them, assigns them a random ID and attaches some event listeners to each. However, I am getting the problem outlined above when I check my code using JSHint. I have looked at other threads for this issue, but I do not fully understand how to apply the answers from there in my code. Below is a section that is relevant to this warning:


//global variables

var buttons = document.getElementsByClassName("btn");
var firstClick = 1; //set firstClick flag to 1 on load
var buttonIDs = [];
var clickedButtonID = null;
var clickedButtonColour = null;
var clickedButtonTitle = null;

function addListenersToAllBtns() {
    //loop over all buttons on page, assign them unique IDs and attach their EventListeners 

    for (let i = 0; i < buttons.length; i++) {

        let btn_id = guidGenerator();

        buttonIDs[i] = btn_id;
        buttons[i].setAttribute("id", btn_id);


        //add to child node to only have the left side of the button clickable
        buttons[i].childNodes[1].addEventListener("click", function () {

            //save button information
            clickedButtonID = btn_id;
            clickedButtonTitle = buttons[i].childNodes[1].childNodes[1].innerHTML;

            //button class format is ".btn colour"
            clickedButtonColour = buttons[i].getAttribute("class").split(" ")[1]; 
            
            console.log("The ID of the clicked button is: ", clickedButtonID, "\n",
                'The colour of the clicked button is ', clickedButtonColour);

            if (firstClick == 1) {
                firstClick = 0;
                window.addEventListener("resize", positionHabitCard);
                document.addEventListener('DOMContentLoaded', positionHabitCard, false);
            }
        });

        buttons[i].childNodes[1].addEventListener("click", showHabitCard);

    }
}

I have tried taking the function definition outside the for loop like below and passing it to addEventListener but then it cannot access buttons[i] and has issues with btn_id (says it is undefined).

function getButtonData() {

    //save button information
    clickedButtonID = btn_id;
    clickedButtonTitle = buttons[i].childNodes[1].childNodes[1].innerHTML;

    //button class format is ".btn colour"
    clickedButtonColour = buttons[i].getAttribute("class").split(" ")[1]; 
    
    console.log("The ID of the clicked button is: ", clickedButtonID, "\n",
        'The colour of the clicked button is ', clickedButtonColour);

    if (firstClick == 1) {
        firstClick = 0;
        window.addEventListener("resize", positionHabitCard);
        document.addEventListener('DOMContentLoaded', positionHabitCard, false);
    }
}

Could someone more experienced take a look at this and help me out? I am very much a newbie when it comes to JS, so please excuse any glaring errors I may have missed.

Thank you very much in advance.

1

There are 1 best solutions below

2
MinusFour On

It's a warning, not an error. I can't really say it's an accurate warning though.

First of all, it's only really "confusing" if you are still using var declarations inside a loop. var declarations are only local to functions and the global scope. So there's no such thing as a var declaration for any loop. You can place a var declaration inside a loop but that won't create multiple variables of it. Instead any reference down the line (say like in a function body) will reference the one and only variable created by the declaration inside the loop.

That can be confusing because any one reference can update the variable. So, the first function created by the first iteration could alter a variable that is being used by every other function inside the loop.

With ES6 you have let and const which introduce block scope which also works within loops. That means a declaration inside a loop that iterates n times can create n variables and each reference inside the block will only apply to that iteration.

You are using let declarations inside the loop so you don't really have a problem there. However, if you were to change let i for var i or let btn_id for var btn_id you'd would see that all your functions created in the loop apply the logic for the last button. That is because every iteration would alter i and btn_id (as there would only be one variable per each across all functions).