Matthew Francis Matthew Francis - 5 months ago 11
HTML Question

Newbie - Manipulating closures and For Loops

The answer to why this code is not working is because: The problem with this method is is you're not providing a function as the second argument. You're calling a function - that function is making things blue. It's not returning a function that is making things blue. So you're making things blue immediately and, when the click happens, there's nothing to call, because the function you called returned nothing.

But I'm lost after the first sentence. could someone dumb this down? perhaps a visual explanation of the code would help!

Code: https://jsfiddle.net/2yfj89af/1/

var submitSOBox = document.getElementsByClassName("submitSOBox");

for (i = 0; i < submitSOBox.length; i++) {
submitSOBox[i].addEventListener('click', SOBoxColor(i));
}

function SOBoxColor(i) {
submitSOBox[i].style.backgroundColor = "blue";
}

Answer

The reason explained: you have this line:

submitSOBox[i].addEventListener('click', SOBoxColor(i));

This calls addEventListener which expects a function as the last argument. You provide SOBoxColor(i), which is not a function, but a value returned by a function -- you call it. To pass a function, you would need to pass something like SOBoxColor, so without calling it. This is needed because your browser needs to know what to call when the click event happens.

Now, passing just SOBoxColor will not do what you want. Yes, it will make that SOBoxColor gets called when a click happens, but you will not have the i value passed to it.

To achieve that, you need a modified version of your function that somehow has the i value pre-filled as argument. Luckily there is a way to create such a modified function with the bind method, which returns the same function, but with some things bound to it:

submitSOBox[i].addEventListener('click', SOBoxColor.bind(submitSOBox[i], i));

The first argument of bind determines what the this object will represent when SOBoxColor is called, and the second argument is what i will be.

Now, this will work.

But you can do it even nicer if you would use the this keyword in your SOBoxColor function, because then you don't even need the i parameter:

function SOBoxColor() {
    this.style.backgroundColor = "blue";
}

... and your binding can also do without the i argument:

submitSOBox[i].addEventListener('click', SOBoxColor.bind(submitSOBox[i]));

Now, it can be done even simpler, because when the click happens, the browser will already provide a nice service to us: it sets the this keyword to the element to which you added the event handler, so in the end it is not even necessary to bind submitSOBox[i] to it explicitly. This will work also:

 submitSOBox[i].addEventListener('click', SOBoxColor);

... provided you changed the SOBoxColor function to work with this.

Comments