0

For easier explanation, please see the corresponding jsFiddle

This is the code I'm calling in a loop:

var eventNames = ["click", "dblclick", "contextmenu"];
for (var i = 0; i < eventNames.length; ++i) {
    var crtName = eventNames[i];
    $("#" + crtName).click(function () {
        alert("Event " + crtName);
    });
}

Sure, when the handler is called, crtName is always "contextmenu" because at this point, the for-loop has ended and i is always pointing to the highest possible value.

Note: In the current example, I'm using the click function from jQuery. In my real application, there's another framework being called to register an event handler. So this is just an example and it cannot be changed. Neither can I add parameters being passed to the handler when the event occurs. Therefore it's not a jQuery question.

As well, it's similar to the question "need help understanding JS code", except for the important fact that I'm not calling my event handler myself!

Basically: I would like the variable crtName to be populated when the handler is being registered, not when it's called.

Community
  • 1
  • 1
Atmocreations
  • 9,923
  • 15
  • 67
  • 102

3 Answers3

2

Issue:

JavaScript's scopes are function-level, not block-level, and creating a closure just means that the enclosing scope gets added to the lexical environment of the enclosed function.

After the loop terminates, the function-level variable crtName has the value contextmenu, and that's what the inner function 'sees'.

So you can do,

var eventNames = ["click", "dblclick", "contextmenu"];

for (var i = 0; i < eventNames.length; ++i) {
    var crtName = eventNames[i];
    attach_event(crtName);
};

function attach_event(crtName) {
    $("#" + crtName).click(function () {
        alert("Event " + crtName);
    });
}

Read More about closures:

  1. Javascript infamous Loop issue?
  2. Javascript closure insideloops - simple practical example
  3. How do JavaScript closures work?

Fiddle

Community
  • 1
  • 1
Deepak Ingole
  • 14,912
  • 10
  • 47
  • 79
0

As Pilot said, you need to use a closure, like this:

(function (crtName) {
    $("#" + crtName).click(function () {
        alert("Event " + crtName);
    });
})(crtName);

This way, you pass crtName to a self invoking function that gets executed with the right event name for each member of the array

Vier
  • 718
  • 2
  • 6
  • 19
-1

Since you are using crtName to refer to the element's ID, just reference this.id inside the event handler

Deepak Ingole
  • 14,912
  • 10
  • 47
  • 79
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • thanks for your message. As written in the example, the jQuery-way is only used to simplify the example code and to create a runnable jsFiddle. Therefore, this isn't a solution. =( – Atmocreations Mar 25 '14 at 11:15
  • If you're using the variable to set the type of event, consider also using `evt.type` to get the event type. – Niet the Dark Absol Mar 25 '14 at 11:19