Can I get a button in shadowDOM to submit a form not in shadowDom?

僤鯓⒐⒋嵵緔 提交于 2021-01-23 04:58:52

问题


I just ran into an interesting situation where I have a submit <button> inside the shadowDOM of a native custom element that is placed inside a <form>.

  <form id="one" action="" method="get">
    <s-button>Select</s-button>
      #shadow-root
        <button>...</button>
    <button>Outside</button>
  </form>

I also have a <button> as a direct child of the <form>.

The child <button> causes the form to submit.

But the <button> in the shadow-root does not.

In a way I guess this makes sense. But has anyone figured out a way to tell the shadow-root <button> to work correctly with the <form> or is this something I will have to handle through JS?


UPDATE

Thanks @Supersharp

Yes, I know click events are blocked at the shadowDOM layer, but I am surprised that there is no way to allow the button to still be a part of the form, something that can be set up through an attribute or a property.

Sure I can capture the click event and then send a new one from this but that does not do the same thing since my event will no longer be user generated and there are a huge set of rules associated with that.

I find it sad that this was not something thought about by the designers when Web Components were designed. This just seems like a flaw in the design.

@Danny,

I think you meant that buttons dispatch click events and not submit events. It is the form that dispatches the submit event. But your example could be closer to what I am after since closest only gives me the form I am a child of.


回答1:


You'll have to handle it through Javascript anyway.

A simple solution is to add a (masked) <button> in the light DOM, and transfer the click event to it.

customElements.define( 's-button', class extends HTMLElement {
    connectedCallback() {
        this.attachShadow( {mode: 'open'})
            .innerHTML = `<button>In Shadow</button>`
        var submit = this.appendChild( document.createElement( 'button' ) )
        this.onclick = () => submit.click()
    }
} )
<form onsubmit="console.log('submitted');return false">
    <s-button>Select</s-button>
    <button>Outside</button>
</form>



回答2:


A button triggers a submit Event (on the FORM element)

Since Events can not pass the shadow DOM boundary (do not bubble up into the parent DOM)

I presume that is why a shadowDOM button (dispatching a submit event) is not received by the FORM element.

Requires Supersharps workaround with a hidden button in the light DOM (which then dispatches a submit event in the parent DOM)

Or (starting from light DOM) you find the (parent) FORM tag and dispatch a submit event yourself:

this.closest('FORM').dispatchEvent(new Event('submit'))


Follow the experts on shadowDOM and FORMs at: https://github.com/w3c/webcomponents/issues/187

customElements.define( 'my-button', class extends HTMLElement {
  connectedCallback() {
    this.attachShadow({mode:'open'}).innerHTML=`<button>Button In Shadow DOM</button>`
    this.onclick = _ => this.closest('FORM').dispatchEvent(new Event('submit'))
  }
})
<form onsubmit="return console.log('submit Event occured')">
    <my-button></my-button>
    <button>button in Document DOM</button>
</form>

Nested shadowDOMs

If the FORM is not a direct ancestor, you can find it with something like: How to reference to a method in parent component from child component with vanilla JS Web Components? (Not any framework or Library)



来源:https://stackoverflow.com/questions/54370436/can-i-get-a-button-in-shadowdom-to-submit-a-form-not-in-shadowdom

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!