Can regular Javascript objects dispatch events or is this only possible for DOM nodes?

StackOverflow https://stackoverflow.com/questions/23690078

  •  23-07-2023
  •  | 
  •  

Pregunta

I've created a Javascript pseudoclass and I want it to be able to dispatch custom events. Unfortunately, it seems like only DOM nodes are able to dispatch events. So, I'm forced to associate a DOM node with every instance of my pseudoclass, so that the DOM node can dispatch events on behalf of my class.

I'd like to be able to add event listeners directly to instances of my pseudoclass. Unfortunately, because the pseudoclass isn't able to dispatch it's own events, I must add the event listeners to the associated DOM nodes instead.

When I do this, my event handler functions receive a reference to the DOM node instead of the pseudoclass instance. I must then determine which pseudoclass instance the DOM node belongs to, before I can call it's methods.

I'm trying to maintain a clean separation between my Javascript and the DOM, wherever possible. Of course there will be times when it will make sense to associate pseudoclass instances with DOM elements, but I don't want this to be an absolute requirement.

My boilerplate code:

jQuery(document).ready(function($){

    var cat = new Animal($('#cat'), 'Larry', 'Meow');

    cat.domElement.on('spoken', function(event){
        var classInstance = $(this).data('instance');
        console.log(classInstance.firstName + ' has spoken');
    });

    cat.speak();

});

My pseudoclass

(function(){

    window.Animal = Animal;

    function Animal(domElement, firstName, sound) {
        // Save a reference to the DOM node
        this.domElement = domElement;

        // Give the DOM node a reference to this class instance
        this.domElement.data('instance', this);

        this.firstName = firstName;
        this.sound = sound;
    }

    Animal.prototype.speak = function() {
        console.log(this.sound);
        this.domElement.trigger('spoken');
    };

}(window));

Side note: I need to support legacy browsers such as IE8. I tried very hard to use the proper Javascript event model, instead of having to rely on jQuery. Unfortunately, I wasn't able to find adequate polyfills for dispatchEvent, addEventListener, removeEventListener, Event, CustomEvent, etc. jQuery provides an excellent abstraction layer with familiar syntax, and my team uses it regularly anyway. However, please let me know if there's a clean, vanilla Javascript solution!

¿Fue útil?

Solución

You can emulate simple event handling relatively easy by yourself:

function Animal(domElement, firstName, sound) {
    this.$$handler = {};
}

Animal.prototype.on = function (eventType, callback) {
    if (!this.$$handler[eventType]) {
        this.$$handler[eventType] = [];
    }
    this.$$handler[eventType].push(callback);
};

Animal.prototype.trigger = function (eventType, args) {
    var i, max_i,
        handler = this.$$handler[eventType];

    if (!handler) {
        return;
    } 
    for (i = 0, max_i = handler.length; i < max_i; i++) {
        handler[i](args);
    }

};

Animal.prototype.speak = function() {
    this.trigger('spoken', {"eventargs": []});
};


//on the instance
cat.on('spoken', function(args){
    var classInstance = $(this).data('instance');
    console.log(classInstance.firstName + ' has spoken');
});

Otros consejos

You don't have to use the DOM as your event generating/handling mechanism. You can write your own, or use something like Backbone.Events which is designed to be mixed into any class.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top