1

I'm trying to emit custom events from my custom object like so:

var CustomObject = function () {
    this.customEvent = new Event('afterInit')
    /* init code goes here*/
    this.dispatchEvent(this.customEvent)
}

But my object cannot dispatch (i.e. dispatchEvent is not a property of my object) and I cannot bind to it. What is the correct syntax for firing custom events from custom objects?

  • Events are part of the DOM spec, not objects. It sounds like you have an X-Y problem. Why can't you accomplish what you need using a callback or promise instead? – BenM Jul 17 '18 at 16:11
  • dispatchEvent doesn't magically exist on any JavaScript object. It is a method of the [EventTarget interface](https://dom.spec.whatwg.org/#interface-eventtarget). – Touffy Jul 17 '18 at 16:11
  • If you want your custom object to be able to listen to DOM events, either make it a subclass of HTMLElement, or implement the complete EventTarget interface on it (not just `dispatchEvent` mind you, that would be misleading). – Touffy Jul 17 '18 at 16:13
  • I see. Thanks for quick responses. I was sure there was a way to do it with events and seemed cleaner than callbacks. Promises it is – Matija Dogan Jul 17 '18 at 16:15
  • I think Promises and AsyncIterables are nicer. But if you'd like to actually use DOM Events, look at this: https://stackoverflow.com/questions/22186467/how-to-use-javascript-eventtarget – Touffy Jul 17 '18 at 16:29

2 Answers2

4

Recently, EventTarget got a constructor, so you can actually use it for your JS object – before it was just an interface used only by DOM elements:

class CustomObject extends EventTarget {
  constructor() {
    super();
    this.customEvent = new CustomEvent("afterinit");
  }

  init() {
    this.dispatchEvent(this.customEvent)
  }
};

let myObject = new CustomObject();
myObject.addEventListener("afterinit", console.log);
myObject.init();

Unfortunately, the support of EventTarget's constructor is not good enough – see the link above –, and it's a Web API, means supported only in a browser's environment.

ZER0
  • 24,846
  • 5
  • 51
  • 54
  • 1
    it's very unlikely we'll see EventTarget outside the browser, but Web APIs can and do end up in Node.js sometimes, like [URL](https://nodejs.org/dist/latest-v10.x/docs/api/url.html#url_the_whatwg_url_api) and probably `fetch` soon ;) – Touffy Jul 17 '18 at 16:38
-1

Objects do not have events. You have to implement that functionality on your own, then you can create new objects that inherit that using the class syntax:

 const handlers = Symbol.for("handlers");

 class EventEmitter {
   constructor(...args) {
     super(...args);
     this[handlers] = new Map;
   }

   on(name, handler) {
     if(!this[handlers].has(name)) {
       this[handlers].set(name, [handler]);
     } else {
       this[handlers].get(name).push(handler);
     }
   }

   trigger(name, ...args) {
     for(const handler of this[handlers].get(name) || [])
        handler(...args);
   }
}

Which you can use as:

const obj = new EventEmitter();
obj.on("test", alert);
obj.trigger("test", "hello world!");

Or with inheritance:

class Custom extends EventEmitter { /*...*/ }
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • I'd be happier if you gave an example of implementing EventTarget instead of the Node.js-style EventEmitter that's already everywhere on SO. – Touffy Jul 17 '18 at 16:25
  • @Touffy ... Voila ... [How to implement an event dispatching system for ES/JS object types?](https://stackoverflow.com/questions/73894457/how-to-implement-an-event-dispatching-system-for-es-js-object-types/74140087#74140087) – Peter Seliger Oct 22 '22 at 13:59