2

This is possibly duplicated, however, things are changing fast in JavaScript world with new browsers. I'm using some resources that used in AS3 a long time ago and now it's finally popular in JavaScript. However, I still can't make events work in my classes. I did this simple example using Mozilla MDN as guide:

var endEvent = new Event("end");

function MyClass(text){
    this.text = text;
    this.show = function(){
        console.log("MyText: "+this.text);
        this.dispatchEvent(endEvent);
    }
}

function End(evt){
    console.log("Event dispatched: "+evt);
}

function run(){
    var MyInstance = new MyClass("I have something to say...");
    MyInstance.addEventListener("end", End, false);
    MyInstance.show();
}

At the first line, Safari returns: "TypeError: '[object EventConstructor]' is not a constructor (evaluating 'new Event("end")')".

It means won't work? Is there a way to create and dispatch custom events in PURE JavaScript (won't use jQuery or anything like)?

Gustavo
  • 1,673
  • 4
  • 24
  • 39
  • If `new Event` is throwing an error in _Safari_, check you have the newest version of the browser and if you do, you may want to submit a bug report to Apple. `new Event` will work in all the main browsers; _Chrome, FireFox and IE9+_ – Paul S. Jul 26 '14 at 00:11

2 Answers2

3

I had this same question a bit ago

Here's the solution I came up with

requires ecmascript >= 5


function Emitter() {
  var eventTarget = document.createDocumentFragment();

  function delegate (method) {
    this[method] = eventTarget[method].bind(eventTarget);
  }

  [
    "addEventListener",
    "dispatchEvent",
    "removeEventListener"
  ].forEach(delegate, this);
}

Now a "class" that uses it

function Example() {
  Emitter.call(this);
}

Let's try it out now!

var e = new Example();

e.addEventListener("something", function(event) {
  alert("something happened! check the console too!");
  console.log(event);
});

e.dispatchEvent(new Event("something"));

Cool!


Let's see it working with your code now. Here's a demo.

// include function Emitter from above

function MyClass(text){

  Emitter.call(this);

  function show() {
    console.log("MyText:", text);
    this.dispatchEvent(new Event("end"));
  }

  this.show = show;
}

function onEnd(event){
  console.log("Event dispatched:", event);
}

function run(){
  var myInstance = new MyClass("I have something to say...");
  myInstance.addEventListener("end", onEnd, false);
  myInstance.show();
}

run();

Output

MyText: I have something to say... 
Event dispatched: Event {
  bubbles: false
  cancelBubble: false
  cancelable: false
  clipboardData: undefined
  currentTarget: null
  defaultPrevented: false
  eventPhase: 0
  path: NodeList[0]
  returnValue: true
  srcElement: null
  target: null
  timeStamp: 1406332794168
  type: "end"
  __proto__: Event
}

Lastly, here's a version of Emitter that's compatible with ecmascript < 5

// IE < 9 compatible
function Emitter() {
  var eventTarget = document.createDocumentFragment();

  function addEventListener(type, listener, useCapture, wantsUntrusted) {
    return eventTarget.addEventListener(type, listener, useCapture, wantsUntrusted);
  }

  function dispatchEvent(event) {
    return eventTarget.dispatchEvent(event);
  }

  function removeEventListener(type, listener, useCapture) {
    return eventTarget.removeEventListener(type, listener, useCapture);
  }

  this.addEventListener = addEventListener;
  this.dispatchEvent = dispatchEvent;
  this.removeEventListener = removeEventListener;
}

See document.createEvent for firing events in legacy browsers

You could make a polyfill like this (untested)

if (typeof Event !== "function") {
  function Event(type) {
    var e = document.createEvent("Event");
    e.initEvent(type, true, true);
    return e;
  }
}
Community
  • 1
  • 1
Mulan
  • 129,518
  • 31
  • 228
  • 259
  • 1
    I agree! Sems interesting, I don't fully understood, but did the test. The error is the same, just pointing to where is "new Event" now. – Gustavo Jul 25 '14 at 23:50
  • In FireFox it works! I did an adaptation to my example and it dispatch the "end" event finally. So it seams it's not so popular yet... – Gustavo Jul 26 '14 at 00:03
  • @GustavoPinent, I provided an adaptation of my answer that closer matches your code. Please see [the fiddle demo](http://jsfiddle.net/naomi/6jF5j/) too. – Mulan Jul 26 '14 at 00:03
  • 1
    Thanks. I'll leave the question alive to see if somebody knows how to make it work in older ecmascript versions. – Gustavo Jul 26 '14 at 00:04
  • @GustavoPinent, I just added a version for older browsers :) The biggest differences are that you can't depend on `Function.prototype.bind` or `Array.prototype.forEach`. – Mulan Jul 26 '14 at 00:08
  • Cool, but there is still the "new Event" problem. It seams a recent DOM specification, so won't work with older browsers. Take a look in the karlipoppins work. – Gustavo Jul 26 '14 at 12:48
  • @GustavoPinent, I have looked at karlipoppins work and I can't even begin to comment on it. It goes so far against the grain of how I work through problems. Anyway, the issue you're referring to is addressed by many polyfill libs. Checkout [modernizr](http://modernizr.com/) as an example. I've also update my answer to show a possible solution for this. – Mulan Jul 27 '14 at 19:41
  • @GustavoPinent, point is, of course there's a ton of factors to be concerned about if you want to support 15+ years of browser versions. Tackling those problems on your own for every piece of code you write isn't something you have to deal with. Check into some of the polyfill libs to make your legacy support development a lot easier. – Mulan Jul 27 '14 at 19:42
  • I love you! It's working! Maybe you misunderstood me, I'm testing with Safari 5.1 (2013) and IE 9 as the oldest browsers supported by my code, and I'm making my own lib to create a standard for my customers. This code for Event it's just the kind of solutions I'm putting together in a single pack (maybe I misunderstood kerlipoppins work). modernizr might be too much, but I'll keep at hand. Thanks again! – Gustavo Jul 28 '14 at 18:12
1

Preaching for my own church here, but I happen to have worked on this very recently and wrote a tiny javascript that handles events and inheritance.

It's all on github if you want to check out some examples:

http://nicolasbize.com/moojs

(contains clickable links)

Gad
  • 41,526
  • 13
  • 54
  • 78
  • I'm working exactly like this. I might be using this solution if you don't mind. Is not the first time I try here: http://stackoverflow.com/questions/22571250/if-eventconstructor-is-not-a-constructor-how-should-i-create-the-event. Hope to succeed this time! – Gustavo Jul 26 '14 at 12:51