WICG / webcomponents

Web Components specifications
Other
4.37k stars 371 forks source link

CustomEvents Add Event Handler in Html #908

Open MichaelPeter opened 3 years ago

MichaelPeter commented 3 years ago

Hello all,

it would save a lot of work if I could add event handlers already in html. Also in regard to third party frameworks like Blazor, Angular, Vue etc.

<my-component onmycustomevent="(function()(e) => alert(`MyEventValue: ${e.detail.myeventvalue}`))();></my-component>

Instead of having to define the eventhandler always in javascript with component.addEventListener()

emilio commented 3 years ago

Nothing prevents the component from doing that right?

MichaelPeter commented 3 years ago

But that requires the component to implement it right?

Lets say I have this test component

customElements.define('webcomp-event', class extends HTMLElement {
    constructor() {
        super(); // always call super() first in the constructor.

        this._clickCount = 0;
        // Attach a shadow root to <fancy-tabs>.
        const shadowRoot = this.attachShadow({ mode: 'open' });
        shadowRoot.innerHTML = `
            <label>
            <input type="checkbox" id="my-checkbox"></input>
            Change to Raise event
            </label>
        `;

        // Internal event listener
        shadowRoot.querySelector('#my-checkbox').addEventListener('click', (e) => {
            this._clickCount++;
            this.customCheckEvent = new CustomEvent("customcheck", {
                detail: {
                    clickCount: this._clickCount,
                    isChecked: e.target.checked
                },
                bubbles: true,
                composed: true,
                cancelable: false,
            });

            this.dispatchEvent(this.customCheckEvent);
            console.log(`input.clickEvent ${e.target.checked}`);
        });
    }
});

So how I would support this behavior? Add attributeChangedCallback on 'on' + eventName and then parse the (javascript-)value? So this is essentially a feature the web component frameworks like lit-html need to support /I need to implement myself?

By supporting it directly in web components, it would be easier for manufacturers to support it by code editors.

Thank you for the help 👍

emilio commented 3 years ago

So this is essentially a feature the web component frameworks like lit-html need to support /I need to implement myself?

I suspect so, it doesn't seem hard to implement some sort of base class that does this. The firefox UI uses similar patterns for "inheriting" attributes and such.

Making this "magic" is probably a breaking change (though I guess there could be some sort of opt-in at the component registration level...), plus you'd probably also want a get onmycustomevent() / set onmycustomevent() etc, right? Those are I suspect even more tricky to implement transparently / magically, they need to live somewhere in the proto chain of the element, so making that happen without anything in the class declaration that you use for registration seems a bit hard.

MichaelPeter commented 3 years ago

Those are I suspect even more tricky to implement transparently / magically, they need to live somewhere in the proto chain of the element, so making that happen without anything in the class declaration that you use for registration seems a bit hard.

Yea, also I am coming from the Microsoft Blazor/WebAssembly World where event handlers work still "completly different". I am not so shure about React, Angular and Vue but I think there they also can be added differently.

So it would be nice if all these frameworks could adapt a simular syntax, if a standard for it is defined.

Greetings Michael

annevk commented 3 years ago

Potentially https://github.com/tc39/proposal-decorators will make this easier, but even then it would be good to see adoption in "userland" before standardizing around it.

domenic commented 3 years ago

Yeah, I've long been a proponent of providing helper APIs to make these sorts of things easier. E.g. attribute/property reflection, or event handler properties. I think beyond precedent in libraries, there's huge precedent in the platform itself.

But, without decorators, the helper APIs are just extremely non-ergonomic. Compare the two samples at https://gist.github.com/domenic/e3e1e034e119826f394480cd9f15e211#proposed-api-shape .

Given that we don't generally want to standardize something twice, and this can be done in userland in the meantime, I think waiting for decorators is the right move.

MichaelPeter commented 3 years ago

So I found out LitElement supports this, there you can subscribe to normal and custom events this way:

<my-component @my-event="(e) => alert(e.detail.text)"></mycomponent>

Still have to find out if this also works in blazor since there the @ is also reserved for c# code in blazor framework

justinfagnani commented 3 years ago

@MichaelPeter please note that the @ syntax is only available in lit-html templates, and not in plain HTML. It also takes a JS reference the the event listener function, not the source text. So this won't work out-of-the-box with Blazor.

It is possible to implement an onxxx event handler property/attribute which will convert a javascript:-prefixed string into a function, which is what @domenic is referring to.

It's a bit tricky to get such a property to behave exactly like the built-in event handler properties in the platform, but it's mostly doable. It's also a source of potential security issues, especially if you don't name the property with an "on" prefix so sanitizers can remove them.

MichaelPeter commented 3 years ago

@justinfagnani : hello Justin, thanks for the explanation. I just wanted to name an example, since @annevk asked for user land examples. If the Syntax is now onmyevent or @myevent is not sooo importaint. Importain is this would be a possibility for a standardized behavior, which frameworks like vue, react, angular or blazor could rely on.