0

I have an event listener which includes an event handler with parameters ... and it works ... and, from what I have read, it is not supposed to. When I include the event handler in an anonymous function, like (I think that) I'm supposed to, it stops working.

I have searched this forum for similar issues and all of the questions are answered the same way (paraphrasing): "if you want parameters in your event handler, you have to put it in an anonymous function."

Apologies if this is a mundane question, I am new to this (and I did search for duplicate questions): But, why does this work and, more importantly, is there a better way to do this?



[Clarifying info: I have 5 buttons on a page, hence the loop. Each button controls a different area of the webpage (but with the same action, change css styling from "display:none" to "display:block") - which is why I need a one-to-one correspondence between an individual button and an individual "details" tag, hence the need for parameters in the event handler. Finally, the buttons toggle, hence the "if ... else".]


p.s I have a put a page online, temporarily, so you can see how it works (it is just a "notes to myself" page and is incomplete) : http://www.mylescallan.com/gameDesign/gameDesignIntroduction.html


var buttons = document.getElementsByClassName("expand"),
    details = document.getElementsByClassName("reveal"),
    i;

function makeClickHandler(details, i) {
    "use strict";
    function myHandler() {
    if (details[i].style.display === 'block') {
        details[i].style.display = 'none';
        buttons[i].innerHTML = "<em>Click Here:</em> To Expand The Source  Code For This Section";
        buttons[i].style.opacity = "1";
    } else {
        details[i].style.display = 'block';
        buttons[i].innerHTML = "<em>Click Here<em>: Don't Forget To Hide This Section, You've Read It";
        buttons[i].style.opacity = "0.5";
    }
};
    return myHandler;
}

for ( i = 0; i < buttons.length; i++) {
buttons[i].addEventListener("click", makeClickHandler(details, i), false);
}
1
  • Another stack overflow question has the answer that I was looking for. The function "myHandler" was unnecessary in my code, and I could have replaced "function myHandler(){...}" with "return function(evt){ ...}" ... still not 100% sure why this works. But I'm getting closer :D Commented May 8, 2015 at 3:32

1 Answer 1

1

if you want parameters in your event handler, you have to put it in an anonymous function.

Not exactly. If you want iteration-dependent parameters in your event handler, you will have to put the handler in its own scope where those parameters are stored.

Now, this scope is often achieved by using an IEFE (see here for examples), which typically is anonymous. However, you can also name them without effecting the handler behaviour.

In your example snippet, none of the functions are anonymous, they are very explicitly named. makeClickHandler() does provide the scope with the i variable, in which the myHandler closure lives. It works, as is expected.

Maybe it helps your understanding when you notice that

function makeClickHandler(details, i) {
    return function myHandler(event) {
        … // use details, i, event
    };
}
for (var i = 0; i < buttons.length; i++)
    buttons[i].addEventListener("click", makeClickHandler(details, i) , false);
//                                                      no call here ^

is equivalent to

function addClickHandler(button, details, i) {
    function myHandler(event) {
        … // use details, i, event
    }
    button.addEventListener("click", myHandler , false);
//                               no call here ^ (that's what is said everywhere)
}
for (var i = 0; i < buttons.length; i++)
    addClickHandler(buttons[i], details, i);
Sign up to request clarification or add additional context in comments.

12 Comments

Thank you for your reply! However, the loop is a "red herring" here (it is why I put the closing function in my handler). My question is solely about parameters in event handlers in an event listener. Every book that I have read (am reading) and many replies to questions on this forum, say explicitly that you should put an anonymous function in the event listener, if you want parameters in your event handler. I'm wondering whether all that advice can be safely ignored, and whether there is a better way to write my code.
What do you mean by "paramters"? If you want to receive the Event argument to your listener function, you just have to put a parameter there: function myHandler(event) { … }. Whether it is named or not does never matter. You always have to pass a function of course (named or anonymous function expression, or one declared elsewhere) - what else would you pass?
makeClickHandler(details, i)
makeClickHandler(details, i) - "details" and "i" are parameters of the function makeClickHandler. I have them as parameters of the makeClickHandler function in my event listener. Which, according to everything that I have read, you are not supposed to (I am currently reading Eloquent Javascript and a book by John Duckett). (For example, you say that event is a parameter of the event handler, which is obvious, but you don't include that when you attach the event handler to the event listener: item.addEventListener("click", clickHandler, false);, for example).
Ah, now I understand what you're getting at :-) The parameters for makeClickHandler are fine, because they are no parameters to your event handler (which is myEventHandler). What would be wrong is addEventListener("click", myEventHandler(event)) - it must be addEventListener("click", myEventHandler), you have to pass a function. That function can be instantiated in place using an (anonymous) function expression, it can a reference to a function declared elsewhere, or it can be the return value of a function call (makeClickHandler(…)). The latter can be confusing though.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.