3

With jQuery you can use .on()/.off()/.trigger() methods on any jQuery object, giving you powerful access to the event system. I'm trying to do something similar in vanilla JavaScript but I keep running into "TypeError: Illegal Invocation". I'm aware this error generally refers to losing a this reference when the method expects one. Using .apply or .call seems to usually do the trick, but I'm still running into problems.

Specifically, I'm trying to create an event enabled "class", which I can then extend other classes from, giving me a way to listen for and trigger events on non-DOM objects. (Yes, I know JS doesn't have real classes. I'm using CoffeeScript and thats the syntactic sugar used there.) Here is the "class" function which creates a new object with the same properties and values as the object passed to the constructor, and provides three methods that .apply() methods from EventTarget.prototype. Any guidance on how to get this working would be immensely appreciated!

EventEnabled = (function() {
  function EventEnabled(obj) {
    var key, val;
    for (key in obj) {
      val = obj[key];
      this[key] = val;
    }
  }

  EventEnabled.prototype.addEventListener = function() {
    return EventTarget.prototype.addEventListener.apply(this, arguments);
  };

  EventEnabled.prototype.removeEventListener = function() {
    return EventTarget.prototype.removeEventListener.apply(this, arguments);
  };

  EventEnabled.prototype.dispatchEvent = function() {
    return EventTarget.prototype.dispatchEvent.apply(this, arguments);
  };

  return EventEnabled;

})();

When I try to call any of those three methods on an instance of EventEnabled, I get a:

"TypeError: Illegal Invocation".

Thanks for any insight into this!

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
nickb
  • 95
  • 1
  • 5
  • 1
    `addEventListener` (and friends) want you to pass a DOM element as `this`, not an instance of your `EventEnabled` class. – gen_Eric Mar 27 '14 at 19:42
  • How are you making instances of `EventEnabled`? What are you passing the constructor? How are you calling the `addEventListener` method of `EventEnabled`? – gen_Eric Mar 27 '14 at 19:48
  • @RocketHazmat **RE: first comment** I was just hoping that wasn't actually being enforced, but if that's the case then I'm out of luck. **RE: second comment** instantiating and calling like so: `var eventedObj = new EventEnabled( obj ); eventedObj.addEventListener("customEvent", function(event){ console.log(event); }, false);` – nickb Mar 27 '14 at 19:56
  • Yeah, you can only call `addEventListener` on DOM elements. jQuery lets you "bind" events to any jQuery object, but that's because it just stores the function in the instance and calls it when triggered. It only uses `addEventListener` with DOM elements. – gen_Eric Mar 27 '14 at 20:00
  • 1
    @RocketHazmat I see, that's unfortunate. Yes, I noticed some odd things when mixing jQuery/vanilla event listeners as [shown here](http://codepen.io/nickbottomley/pen/BbpnF). I guess I'll come up with some other approach, thanks for the help. – nickb Mar 27 '14 at 20:13
  • possible duplicate of [How to use JavaScript EventTarget?](http://stackoverflow.com/questions/22186467/how-to-use-javascript-eventtarget) – Bergi Mar 27 '14 at 22:04
  • @Bergi if you want to answer that EventTarget is an interface not a constructor, which I think would be helpful for someone thinking about going down the same path that I did, I'd be happy to accept that answer. – nickb Mar 28 '14 at 19:28

1 Answers1

8

EventTarget is only an interface which is implemented on native DOM objects, not a constructor that is available to javascript. While it might be available in the global scope, you cannot use it for instantiating instances of it.

Also, you can apply its methods only on objects that have natively implemented that interface (like DOM elements), not on an arbitrary instance of your EventEnabled constructor. You will either need to create an internal node, or you will need to implement your own event dispatching system (if you don't want to use any of the many available libraries).

Bergi
  • 630,263
  • 148
  • 957
  • 1,375