Gustavo
Gustavo

Reputation: 1683

How to work with events in pure JavaScript?

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)?

Upvotes: 2

Views: 1661

Answers (2)

Mulan
Mulan

Reputation: 135187

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;
  }
}

Upvotes: 3

Gad
Gad

Reputation: 42306

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)

Upvotes: 1

Related Questions