Skip to content

Add an option for form-associated custom-elements #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Residu opened this issue Aug 16, 2021 · 2 comments
Open

Add an option for form-associated custom-elements #114

Residu opened this issue Aug 16, 2021 · 2 comments

Comments

@Residu
Copy link

Residu commented Aug 16, 2021

Hi,
i actually trying to link my web-components to native forms.
It seems that the solution is in this API -> https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals

Actually this method works on my vue component but the internals_.form has this exception
"Uncaught DOMException: Failed to read the 'form' property from 'ElementInternals': The target element is not a form-associated custom element."

This is caused because the static formAssociated = true; cant be set.

I'm not sure you can do anything on this, because i dont really understand on which scope this actually works.
Thanks for reading, cant wait to read your answers.

@urukai
Copy link

urukai commented May 5, 2022

Have you found a solution for this?

@Residu
Copy link
Author

Residu commented May 9, 2022

Have you found a solution for this?

We finally have decided to go on another solution.
When the component is initialized as a webcomponent (this.$el.getRootNode()?.host) we search in dom the closest form (this.$el.getRootNode()?.host?.closest('form')) then create a copy of our current component HTML element and append it into the form found earlier. Event triggered on the vue component are reproduced on the copy.

Here is an example of our submit button used as a webcomponent.

<template>
  <button :type="type" @click="handleClick">
       Coucou
   </button>
</template>
export default {
    props: {
        type: {
            default: 'button',
            validator(value) {
                return ['button', 'reset', 'submit'].includes(value);
            },
        },
    },
    data() {
        return {
            hasBeenClicked: false,
            hasNativeHTMLClone: false,
        };
    },
    updated() {
        this.createWebComponentFakeButton();
    },
    methods: {
        initializeFakeButton() {
            const form = this.$el.getRootNode()?.host?.closest('form');
            this.cloneAndHideButton(form);
            this.addHTMLComment(form);
        },
        handleClick(event) {
            this.hasBeenClicked = true;
            this.$emit('click', event);

            if (this.hasNativeHTMLClone) {
                this.hasNativeHTMLClone.click();
            }
        },
        cloneAndHideButton(form) {
            const clonedButton = document.createElement('button');
            clonedButton.type = 'submit';
            clonedButton.style.display = 'none';
            form.append(clonedButton);

            this.hasNativeHTMLClone = clonedButton;
        },
        addHTMLComment(form) {
            const commentText = 'Generated by uc-button for compatibility';
            const comment = document.createComment(commentText);
            form.append(comment);
        },
        createWebComponentFakeButton() {
            // A native button is needed to submit the form
            // Web Component button cannot interact with native HTML form
            const isWebComponentFirstRender = !this.hasNativeHTMLClone;
            const isWebComponent = this.$el.getRootNode()?.host;

            if (
                isWebComponent &&
                isWebComponentFirstRender &&
                this.type === 'submit'
            ) {
                this.initializeFakeButton();
            }
        },
    }
}

Hope it helps, let me know if i forgot something or if something is not clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants