Reputation: 23
When I search for custom events on JavaScript classes, I get a lot of old or incomplete results. MDN shows a custom event off of a dom element. Stackoverflow's top result is almost ten years old and it uses the pre-ES6 syntax.
Is there a way of doing something like:
class Dog
{
constructor(name)
{
this.name = name;
}
//something to expose bark event
}
const buddy = new Dog('buddy');
buddy.addEventListener("bark", function(e) {
console.log(`${this.name} barked!`);
});
Upvotes: 2
Views: 3614
Reputation: 130
@varaprasadh approach helped me get started, but lacked accumulating multiple events. Modified to also allow remove listener that functions similar to on DOM events to get rid of one based on callback.
class Dog {
constructor() {
this.listeners = {};
}
emit(method, payload = null) {
if (this.listeners.hasOwnProperty(method)) {
const callbacks = this.listeners[method];
for (let [key, callback] of Object.entries(callbacks)) {
if (typeof callback === 'function') {
callback(payload);
}
}
}
}
addEventListener(method, callback) {
if (!this.listeners.hasOwnProperty(method)) {
this.listeners[method] = {}
}
this.listeners[method][callback] = callback;
}
removeEventListener(method, callback) {
if (this.listeners.hasOwnProperty(method)) {
delete this.listeners[method][callback];
}
}
}
Upvotes: 0
Reputation: 141
Extend EventTarget class to get all event functions:
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/EventTarget
Upvotes: 1
Reputation: 505
But in your snippet, you wanted to have dog.bark(), in that case see below
class Dog {
addEventListener(method,callback) {
this[method] = callback;
}
removeEventListener (method) {
delete this[method];
}
}
The above will work as
const dog = new Dog();
dog.addEventListener('bark', ()=>console.log("bow"));
dog.bark() // logs => bow
dog.addEventListener('somethingsomething', ()=>{ /*do something*/ })
dog.removeListener('bark');
We can implement tiny class as EventEmitter pattern
class Dog {
constructor() {
this.listeners = {};
}
emit(method, payload = null) {
const callback = this.listeners[method];
if(typeof callback === 'function'){
callback(payload);
}
}
addEventListener(method,callback) {
this.listeners[method] = callback;
}
removeEventListener (method) {
delete this.listeners[method];
}
}
And we can use this class like this
const dog = new Dog();
dog.addEventListener('bark',(customSound)=>console.log(customSound || "Bow Bow"));
dog.addEventListener('eat', ()=>console.log("eating yum yum") );
dog.emit('bark') // logs => Bow Bow
dog.emit('bark', 'i can talk humans') // logs => i can talk humans
dog.emit('eat');
dog.removeEventListener('bark');
Note: it's raw implementation, not production ready code. Thanks.
Upvotes: 4
Reputation: 207547
There are no events with a class. You can implement something that registers functions and you can call them when the method is triggered. Basic idea:
class Animal {
#registered = {};
constructor(name)
{
this.name = name;
}
addEventListener(name, callback) {
if (!this.#registered[name]) this.#registered[name] = [];
this.#registered[name].push(callback);
}
triggerEvent(name, args) {
this.#registered[name]?.forEach(fnc => fnc.apply(this, args));
}
}
class Dog extends Animal
{
constructor(name)
{
super(name);
}
bark(){
console.log('bark was called');
this.triggerEvent('bark');
}
eat(what){
console.log('eat was called', what);
this.triggerEvent('eat', [what]);
}
}
const buddy = new Dog('buddy');
buddy.addEventListener("bark", function() {
console.log(`${this.name} barked!`);
});
buddy.addEventListener("eat", function(item) {
console.log(`${this.name} ate a ${item}!`);
});
buddy.bark();
buddy.eat('bone');
Upvotes: 2