1

I am encountering a weird issue while trying to register and fire events in jQuery. My sample code stub is this:

events = {"changeMode": ["mode1"], "changeKeymap": ["keymap1"]}

for(var event in events) {
  var listeners = events[event];
  for (i=0; i<listeners.length; i++)
  {
    var listn = listeners[i]
    console.log("Activate listener", listn, " For event: ", event);
    $("#testing").on(event, function(e, d) {
      console.log("Event: ", event);
      console.log("Listener invoked is: ", listn);
      console.log("Event which is passed is: ", e);
      console.log("Data is: ", d);
    });
  }
}

$("#testing").trigger("changeMode", "random data");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="testing"></div>

As you can see, while I am trying to invoke the "changeMode", the listener that is actually getting invoked is "changeKeymap". Actually the listener invoked is the last listener that is defined so I am assuming that somehow it is overwriting other listeners. (I actually have much larger code but essentially this is what the bug I am encountering boils down to.) Can anyone suggest what is happening.

Here is JSFiddle: https://jsfiddle.net/7xyyggz8/

EDIT:

The event fired is correct as suggested by Joel. However the listener that invoked in response to that is somehow incorrect.

EDIT 2:

Updated fiddle and code to use vars.. still encountering the same issue

Vedanshu
  • 617
  • 1
  • 7
  • 20

2 Answers2

1

If you look closely you'll see that changeMode was indeed fired. Drill down into the jQuery objects and you'll see it identified. The reason it doesn't LOOK like it's being fired is that you're using an external variable to identify the name.

This line:

console.log("Listener invoked is: ", listn);

is using the listn variable whose last value is changeKeymap. If you change your function to be like:

var eventName = listn;
console.log("Listener invoked is: ", eventName);

It should report as you expect.

Note: A screen paste of the drill down of the actual jQuery event.

enter image description here

Joel Etherton
  • 37,325
  • 10
  • 89
  • 104
  • I tried your suggestion in this fiddle https://jsfiddle.net/7xyyggz8/ but apparently still the changeKeyMap is firing. You can check this from developer console. Can you elaborate a bit more – Vedanshu Sep 11 '15 at 12:45
  • @Vedanshu: You've made the same mistake with the `event` variable. Use chrome, drill down into the jQuery object. I'll post an update in my answer shortly of what I see from your fiddle. – Joel Etherton Sep 11 '15 at 12:50
  • I need to be less confusing in my question language. I will edit it now.I know that event fired is changeMode, however my question is why the listener which is invoked in response to that event is not correct. AFAIK I am registering correct event with correct listener. In my actual code, the hash is not of strings but of function object which I invoke here instead of doing console.logs. Does this help – Vedanshu Sep 11 '15 at 12:56
  • It doesn't really help, but I would suggest your problem is still what I'm identifying here. I promise you, if you're triggering `changeMode` that is the event that is triggering. What you very likely have is a delegate assignment that is using a global variable that gets changed by the final iteration of your for loop. Make sure that any variable you are using from within a delegate is using encapsulated or passed variables. Do not rely on external or globals. – Joel Etherton Sep 11 '15 at 12:58
0

Eventually the problem was figured out to be similar to this one:

JavaScript closure inside loops – simple practical example

This was on the lines of what Joel suggested. Underscore's _.each() function and coffee script's for....do block does this natively.

Community
  • 1
  • 1
Vedanshu
  • 617
  • 1
  • 7
  • 20