custom-elementcustom-events

custom element, custom event handler attributes


Built in browser elements have event attributes which execute arbitrary javascript as described below

https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Event_handlers

Is there any way to create a custom element with a similar behaving custom event handler attribute, and is there a standard pattern for doing so? Where the {some custom eventType}="{some code}" executes with the correct values in scope and the this binding set correctly.

<some-custom-element oncustomevent="alert('worked')" />

Solution

  • First question is: Do you really want to allow executing code from a string? Because it requires eval()

    There is nothing wrong with using eval() when you understand the implications:

    Trigger dynamic (string) code:

      function triggerEvent(name, code = "console.warn('No code parameter')") {
        console.log(name, this);
        if (this === window) console.warn('no element scope');
        try {
          if (typeof code === "string") eval(code);
          else console.warn("code is not a string")
        } catch (e) { console.error(e) }
      }
      customElements.define("my-element", class extends HTMLElement {
        static get observedAttributes() {
          return ['onevent'];
        }
        constructor() {
          super();
          this.onclick = () => triggerEvent.call(this, "element Click", "console.log('from element click')");
        }
        connectedCallback() {
          document.addEventListener("onevent", evt => {
            triggerEvent.call(this, "EventListener", evt.detail);
          })
        }
        attributeChangedCallback(name, oldValue, newValue) {
          if (name === "onevent") {
            triggerEvent.call(this, "attributeChangedCallback", newValue);
          }
        }
        set onevent(newValue) {
          triggerEvent.call(this, "setter", newValue);
        }
      });
    
      setTimeout(() => document.dispatchEvent(new CustomEvent("onevent", {
          detail: "console.log('from dispatchEvent detail')"
        })), 2000); //execute after elements listen
    <my-element onevent="console.log('from element attribute')">click my-element</my-element>
    <button onclick="document.querySelector('my-element').onevent='console.log(&quot;from button&quot;)'"
    >Call setter</button>

    JSFiddle playground at: https://jsfiddle.net/WebComponents/ezacw5xL/