How to dispatch event from a function instead of window

Viewed 2007

The below works fine and my event listener gets the custom event because it's dispatched the event from the window and my event listener is listening for loading on the window, all good.

const MyLib = mylib();
  function mylib() {
    const res = {
      init: (data) => {
        let loading = new CustomEvent('loading', {detail: { loading: true }});
        window.dispatchEvent(loading);
      }
    }
  return res;
}

event listener

 window.addEventListener('loading', handleLoading);

How can I change it to MyLib.addEventListener instead of window.addEventListener?

and..

window.dispatchEvent(loading); to MyLib.dispatchEvent(loading);

The error I get is TypeError: MyLib.addEventListener is not a function

The answer below works in a class, but id like to know if this is possible without using a class.

2 Answers

In order to dispatch and listen to events on an object, the object will need to inherit from the EventTarget interface.

class MyLib extends EventTarget {
    constructor() {
        super();
    }

    init(data) {
        let loading = new CustomEvent('loading', { detail: { loading: true } });
        this.dispatchEvent(loading);
    }
}

// somewhere myLib is an instantiation of MyLib

useEffect(() => {
    myLib.addEventListener('loading', handleLoading);
    return () => {
        myLib.removeEventListener('loading', handleLoading);
    };
}, []);

Proxy can be used to achieve the requirements.

Here's a snippet that wraps the original MyLib object in a Proxy, whose get trap is activated when accessing addEventListener or dispatchEvent.

function mylib() {
  const res = {
    init: (data) => {
      let loading = new CustomEvent('loading', {detail: { loading: true }});
      MyLib.dispatchEvent(loading);
    }
  }
  return res;
}

const MyLib = new Proxy(mylib(), {
  get: function(target, prop) {
    if (prop === `addEventListener`) {
      return (...args) => window.addEventListener(...args);
    } 
    if (prop === `dispatchEvent`) {
      return (...args) => window.dispatchEvent(...args);
    }
    return target[prop];
  }
});

MyLib.addEventListener('loading', () => { console.log("Hello world !!!") });
MyLib.init();
Related