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!
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');
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With