Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

addEventListener on custom object

I've created an object that has several methods. Some of these methods are asynchronous and thus I want to use events to be able to perform actions when the methods are done. To do this I tried to add the addEventListener to the object.

jsfiddle

var iSubmit = {     addEventListener: document.addEventListener || document.attachEvent,     dispatchEvent: document.dispatchEvent,     fireEvent: document.fireEvent,          //the method below is added for completeness, but is not causing the problem.      test: function(memo) {         var name = "test";         var event;         if (document.createEvent) {             event = document.createEvent("HTMLEvents");             event.initEvent(name, true, true);         } else {             event = document.createEventObject();             event.eventType = name;         }         event.eventName = name;         event.memo = memo || { };          if (document.createEvent) {             try {                 document.dispatchEvent(event);             } catch (ex) {                 iAlert.debug(ex, 'iPushError');             }         } else {             document.fireEvent("on" + event.eventType, event);         }     } }  iSubmit.addEventListener("test", function(e) { console.log(e); }, false);   //This call is added to have a complete test. The errors are already triggered with the line before this one.  iSubmit.test(); 

This will return an error: Failed to add eventlisterens: TypeError: 'addEventListener' called on an object that does not implement interface EventTarget."

Now this code will be used in a phonegap app and when I do, it is working on android/ios. During testing, however, it would be nice if I could get it to work in at least a single browser.

PS> I know I could enable bubbling and then listen to the document root, but I would like to have just a little bit OOP where each object can work on its own.

like image 237
Hugo Delsing Avatar asked Dec 30 '13 08:12

Hugo Delsing


People also ask

Can you add an event listener to an object?

You can add event listeners to any DOM object not only HTML elements. i.e the window object. The addEventListener() method makes it easier to control how the event reacts to bubbling.

What is the benefit of using addEventListener instead of inline event handlers?

addEventListener() has multiple advantages: Allows you to register unlimited events handlers and remove them with element. removeEventListener() . Has useCapture parameter, which indicates whether you'd like to handle event in its capturing or bubbling phase.


2 Answers

addEventListener is intended for DOM Elements that implements certain event-related interfaces. If you want an event system on pure JavaScript objects, you are looking for a custom event system. An example would be Backbone.Events in Backbone.js. The basic idea is using an object as a hash to keep track of registered callbacks.

Personally I use this: emitter.

It's a fairly simple and elegant solution - with sweet short method names like on(), off() and emit(). you can either create new instances with new Emitter(), or use Emitter(obj) to mix event capabilities into existing objects. Note this library is written for use with a CommonJS module system, but you can use it anywhere else by removing the module.exports = ... line.

like image 115
Evan You Avatar answered Oct 10 '22 10:10

Evan You


If you don't need true event features(such as bubbling, stopPropagation), then you can implement your own events. addEventListener is just an API of the DOM, so you don't really need it for your own objects outside the DOM. If you want to create an evented pattern around an object, here's a good way to do it that does not require any extra browser APIs and should be very backwards-compatible.

Let's say you have an object where you want a bunch of events to be triggered when the dispatch method is called:

var OurDispatcher, dispatcher;  OurDispatcher = (function() {   function OurDispatcher() {     this.dispatchHandlers = [];   }    OurDispatcher.prototype.on = function(eventName, handler) {     switch (eventName) {       case "dispatch":         return this.dispatchHandlers.push(handler);       case "somethingElse":         return alert('write something for this event :)');     }   };    OurDispatcher.prototype.dispatch = function() {     var handler, i, len, ref;     ref = this.dispatchHandlers;     for (i = 0, len = ref.length; i < len; i++) {       handler = ref[i];       setTimeout(handler, 0);     }   };    return OurDispatcher;  })();  dispatcher = new OurDispatcher();  dispatcher.on("dispatch", function() {   return document.body.innerHTML += "DISPATCHED</br>"; });  dispatcher.on("dispatch", function() {   return document.body.innerHTML += "DISPATCHED AGAIN</br>"; });  dispatcher.dispatch(); 

It really doesn't have to be more complicated than that, for the most part. This way you have some decent control over your events and you don't need to worry about backward-compatibility or external libraries because everything there is widely supported. Technically, you could even do without setTimeout and handle your callbacks without any APIs. Anything else like stopPropagation() would have to be handled yourself.

https://jsfiddle.net/ozsywxer/

There are, of course, polyfills for CustomEvent, but unless I need advanced event features, I prefer to wrap my own eventing system into a "class" and extending other classes/functions with it.

Here's the CoffeeScript version, which is what the JavaScript is derived from: https://jsfiddle.net/vmkkbbxq/1/

^^ A bit easier to understand.

like image 43
Ravenstine Avatar answered Oct 10 '22 09:10

Ravenstine