skip to Main Content

I’ve written my own JavaScript class (for a custom web component). It raises a couple of events. For instance: TagChanged

To listen to this event, I (obviously) do this:

myObject.addEventListener('TagChanged'), (e) => doSomething());

But is it possible to have something like:

myObject.onTagChanged = (e) => doSomething();

The default DOM elements have things like onClick and onKeyDown. Are they using some other architecture?

2

Answers


  1. You’d could implement something yourself, like this:

    class MyComponent extends HTMLElement {
        __ontagchanged = null;
    
        get ontagchanged() {
            return this.__ontagchanged;
        }
        set ontagchanged(fn) {
            // remove old listener, if applicable
            if (this.__ontagchanged) {
                this.removeEventListener('tagchanged', this.__ontagchanged);
            }
    
            // add new listener, if applicable
            if (typeof fn === 'function') {
                // create a unique function to prevent conflicts when using
                // the same function with the add/removeEventListener interface
                this.__ontagchanged = e => fn(e);
                this.addEventListener('tagchanged', this.__ontagchanged);
            } else {
                this.__ontagchanged = null;
            }
        }
    }
    
    Login or Signup to reply.
  2. default DOM elements onClick and onKeyDown. Are they using some other architecture?

    Yes, Browser code us mortals can not access

    But that Browser code also adds a handleEvent on every JavaScript Object

    From MDN – add EventListener

    The method addEventListener() works by adding a function, or an object that implements a handleEvent() function, to the list of event listeners for the specified event type on the EventTarget on which it’s called. If the function or object is already in the list of event listeners for this target, the function or object is not added a second time.

    So you can do

    this.addEventListener("myEvent", this) // calls 'handleEvent' on 'this' Object by default
    

    which (by default) calls handleEvent

    handleEvent(evt) { // handleEvent is called by default on every JavaScript Object!
      if(this["event_" + evt.type]) this["event_" + evt.type](evt) // check if "event_NNN" method exists
    }
    

    Then triggers your method:

    event_myEvent(evt) {
      // your event handling
    }
    

    Full code

      customElements.define("handle-event", class extends HTMLElement {
          handleEvent(evt) { // handleEvent is called by default on every JavaScript Object!
            if(this["event_" + evt.type]) this["event_" + evt.type](evt) // check if "event_NNN" method exists
          }
          event_myEvent(evt) {
            let el = evt.composedPath()[0] // Event escaped shadowRoot, clicked on DIV el
            let color = el.colors.shift();
            el.colors.push(color)
            console.log(el.nodeName, color)
            el.style.background = color;
          }
          connectedCallback() {
            this.addEventListener("myEvent", this) // calls 'handleEvent' on 'this' Object/Class by default
    
            const createElement = (tag, props = {}) => Object.assign(document.createElement(tag), props)
            let newDIV = (name) => {
              const divEvent = new CustomEvent("myEvent", {
                bubbles: true,
                composed: true, // listener is on <handle-event> not on shadowRoot, needs to escape shadowRoot
                detail: {},
              })
                const div = createElement("div", {
                textContent: name,
                        colors : ["red","yellow","blue"],
                onclick: (evt) => div.dispatchEvent(divEvent),
              })
              return div;
             }
            this.attachShadow({mode:"open"}).append(
              createElement("style", {
                textContent: `div { cursor:pointer; background:teal; color:black; padding:10px }`,
              }),
              ...["FOO","BAR","BAZ"].map( name => newDIV(name))
            )
          }
        },
      )
    Click row to cycle colors
    <handle-event></handle-event>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search