Skip to content
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

Need callback for form submit data #187

Closed
hayatoito opened this issue Jul 6, 2015 · 106 comments
Closed

Need callback for form submit data #187

hayatoito opened this issue Jul 6, 2015 · 106 comments

Comments

@hayatoito
Copy link
Contributor

@hayatoito hayatoito commented Jul 6, 2015

Title: [Custom]: Need callback for form submit data (bugzilla: 24603)

Migrated from: https://www.w3.org/Bugs/Public/show_bug.cgi?id=24603


comment: 0
comment_url: https://www.w3.org/Bugs/Public/show_bug.cgi?id=24603#c0
Erik Arvidsson wrote on 2014-02-10 16:09:15 +0000.

Right now there is no way to have custom elements include data in form submissions. We should add another callback for this

I believe we need to add a callback that is called before the submit event.

Strawman:

document.registerElement('input', {
prototype: {
proto: HTMLElement.prototype,
beforeSubmitCallback: function() {
switch (this.type) {
case 'checkbox';
if (this.checked)
return this.value;
return undefined;
...
}
}
}
});

Basically, the contract is that the return value of the callback is used a the form value. If undefined is returned nothing is serialized.

This is of course a bit too simplistic but it might be enough to get started.

Things to keep in mind:

  • Radio buttons need to check outside itself
  • input[type=file]. Return Blob|File|data url?
  • input[multiple]. Array of values?

comment: 1
comment_url: https://www.w3.org/Bugs/Public/show_bug.cgi?id=24603#c1
Boris Zbarsky wrote on 2014-02-10 16:20:44 +0000.

If is a subclass of , why can't it just set the .value to the thing it wants to submit?

If it's not a subclass of , you have other problems too, like form validation not knowing anything about it and so forth...


comment: 2
comment_url: https://www.w3.org/Bugs/Public/show_bug.cgi?id=24603#c2
Erik Arvidsson wrote on 2014-02-10 16:30:48 +0000.

I agree it might be simpler to just subclass input but at some point we should explain how input is implemented too. That also includes explaining form validation and requestAutoComplete and probably tons of other things.


comment: 3
comment_url: https://www.w3.org/Bugs/Public/show_bug.cgi?id=24603#c3
Boris Zbarsky wrote on 2014-02-10 16:37:53 +0000.

Sure. If we do that we need to make all the relevant algorithms robust to script randomly doing unexpected things. E.g. getting the value from an input can change the values of other inputs if it's done in arbitrary script....

The way input is implemented in practice, in ES terms, is that it has private slot (closure variable, weakmap entry, whatever) that stores a value string, and various form operations can retrieve that string without running any untrusted (from the point of view of the form) script in the process. Whatever setup we come up with for explaining input would be best if it preserved those invariants....


comment: 4
comment_url: https://www.w3.org/Bugs/Public/show_bug.cgi?id=24603#c4
Anne wrote on 2014-02-12 18:16:49 +0000.

What about form association and label association? It seems you need hooks for those too.


comment: 5
comment_url: https://www.w3.org/Bugs/Public/show_bug.cgi?id=24603#c5
Dimitri Glazkov wrote on 2014-05-08 20:51:20 +0000.

There's another proposal here: http://lists.w3.org/Archives/Public/public-webapps/2014JanMar/0448.html

@StokeMasterJack
Copy link

@StokeMasterJack StokeMasterJack commented Jun 29, 2016

Here is my proposal for addressing this issue:

http://dave-ford.blogspot.com/2016/06/web-components-and-form-submit-fields.html

@domenic
Copy link
Contributor

@domenic domenic commented Sep 19, 2016

Custom elements F2F: we would like this! Previously, https://lists.w3.org/Archives/Public/public-webapps/2014JanMar/0448.html

Current thinking is:

  • Probably this should be FormData based
  • We should refactor the HTML spec to have "form data steps" per element to make the design a bit clearer (https://html.spec.whatwg.org/multipage/forms.html#constructing-form-data-set)
  • Ideally we'd like to have a setValue/getValue pair so that this could also handle form restoration when doing back/forward/reopening the browser/etc.
  • We're not sure how to best guide authors to having unique names for their fields. (E.g. using the name attribute or some derivative of it like type=image does with name + "x"/"y".)
@rniwa
Copy link
Collaborator

@rniwa rniwa commented Sep 20, 2016

The last point is why we decided to use string & JSON for the value so that we can use name attribute of the element as done for any builtin element.

Using FormData is slightly nicer because it can contain multiple name-value pairs for when a compound element such as a credit-card component needs to submit multiple data fields. But letting users of a component specify the value might be more valuable than each value being submitted as a separate name-value pair. Also, user of such a component can always split the JSON into individual name-value pairs during submit event although having to parse the JSON there is kind of gross.

Yet anther option is to let users of component specify names for each value the component supplies but this is very different from the way builtin elements work so probably not a good idea.

@lukasoppermann
Copy link

@lukasoppermann lukasoppermann commented Oct 13, 2016

@domenic if it is FormData based it would still submit normally when pressing the submit button, correct?

@domenic
Copy link
Contributor

@domenic domenic commented Oct 13, 2016

Yes

@lukasoppermann
Copy link

@lukasoppermann lukasoppermann commented Oct 13, 2016

Awesome. But since you tagged it v2: If it does come into the specs it will probably be a year or more, correct? Since v1 is just releases and not even really implemented anywhere.

@domenic
Copy link
Contributor

@domenic domenic commented Oct 13, 2016

No, "v2" is a misnomer. The specs are living and see continuous changes, and implementations implement those changes as they can prioritize them, according to each implementation's individual release cycle. In the issue tracker, "v2" means something roughly like "not part of the initial set of features that we reached consensus on in the January 2016 face to face meeting".

@lukasoppermann
Copy link

@lukasoppermann lukasoppermann commented Oct 13, 2016

Ahh, I see. Thanks for the clarification. Where can I best track the progress of this, to see if/when it will come?

@domenic
Copy link
Contributor

@domenic domenic commented Oct 13, 2016

Watching this issue is the best way to get updated on spec progress. After that, the procedure is specific to each browser; places like the various browser status trackers or bug trackers will be where implementation-specific discussion happens. That's kind of outside the scope of this repo though.

@PleasantD
Copy link

@PleasantD PleasantD commented May 2, 2017

Has there been any progress on this?

We want to develop internal components that are project/framework agnostic. Ideally we want to be able to support Angular, React, and MVC patterns. The last one is the sticking point. Several of the components I want to build are basically form elements so I should be able to drop them in a form and submit with no additional code needed.

Is there a workaround to support submitting the component's values with the enclosing form on submit?
What about self-validating components, where the component can prevent form submission if it is in an invalid state?

@treshugart
Copy link

@treshugart treshugart commented May 2, 2017

@PleasantD the only workarounds we've been able to find are to replicate the behaviour of form elements (which requires you to also to replicate <form />) or to not use shadow DOM at all.

Replicating form and input behaviour is robust, and allows you to keep shadow DOM encapsulation, but can work well when implemented correctly and edge-cases are tested. We've documented roughly how to do this here: https://skatejs.gitbooks.io/skatejs/content/docs/recipes/form-behaviour-and-the-shadow-dom.html. This can work with any web component library, not just Skate. The downfall here is that your custom <my-form /> will be tightly coupled to your <my-input /> elements. Your custom input elements won't be able to be dropped into a standard <form /> element, thus not reusable unless your consumers also use your custom form element.

Not using shadow DOM works well for leaf nodes. Luckily, most form elements are leaf nodes. However, it falls short when you want to use the custom element in a library that takes over control of childNodes, like React. I know libraries like Incremental DOM and Preact have since lightened up how they destroy nodes they don't know about, but I'd err on the side of replicating form behaviour until this gets implemented.

You could try and use the is attribute. This would in fact be the most elegant approach, but you'll never be able to remove the polyfill because, at least, Safari will never implement it.

@rniwa
Copy link
Collaborator

@rniwa rniwa commented May 9, 2017

We've made a concrete proposal three years ago in https://lists.w3.org/Archives/Public/public-webapps/2014JanMar/0448.html

@tkent-google
Copy link
Contributor

@tkent-google tkent-google commented Apr 26, 2019

Minutes of Spring 2019 F2F

Re: Form-associated non-custom elements, ElementInternals for built-in elements

It is an issue separated from form-associated custom element. So we can discuss it after finishing this issue.
We need to take care of many edge cases. For example, if <a> was form-associated, name attribute would have two meanings.
I'm afraid it will make the specification and implementations much complicated.

Re: Form validation for compound controls

Suppose that we have a form-associated custom element with three internal fields.

<card-input required>
  #shadow-root
    <input id=cardno pattern="[0-9]{15,16}" required>
    <input id=expiration type=month required>
    <input id=cvc pattern="[0-9]+" required>
</card-input>

The owner <form> of <card-input> doesn't take care of these internal fields at all. So the implementation of <card-input> should call ElementInternals.setValidity() if one of them is invalid.

Validation UI would have a trouble. The current proposal and the Chrome implementation just show a validation UI on <card-input>. However, it should be shown on an invalid internal field.
A possible solution would be to add an optional Element argument to ElementInternals.setValidity(). this.#internals.setValidity({valueMissing: true}, 'Please fill out this field with the expiration month of the card', this.#expiration); will show a validation popup on expiration field.

What do you think?

@muan
Copy link

@muan muan commented Apr 26, 2019

Apologies if this has been discussed. I couldn't find them. In testing form-associated custom elements I ran into the following two cases:

  • Looks like implicit submission does not get triggered on form-associated Custom Elements in Chrome's implementation. Should they be? Or is there already a way to hook that up?

  • It doesn't seem like autofocus is supported either. Should they be, like other form controls? Reference.

@domenic
Copy link
Contributor

@domenic domenic commented Apr 26, 2019

I'll defer to @tkent-google as the real expert, but some quick notes while he's away for the weekend:

  • Implicit submission is an interesting question. We discussed this briefly in whatwg/html#4187 (comment) . You could probably make this work manually with a keydown listener for the Enter key. It sounds like you think it's worth making this work more generally? I was under the impression web developers did not like this feature but that's based only on vague memories.

  • Autofocus spec seems weird. The attribute is only defined for form controls, but the processing model never checks if something is a form control. My guess is that since the spec is confusing/incomplete, it was easy to miss this while updating the spec and implementation. But @tkent-google can confirm.

@muan
Copy link

@muan muan commented Apr 26, 2019

You could probably make this work manually with a keydown listener for the Enter key.

Making this work manually and matching the implicit submission behavior would require us to query for the default button as submitter, and submit its value too (via whatwg/html#4187 I guess).

It sounds like you think it's worth making this work more generally?

Given the above, yes, it'd be more ideal if this is handled automatically with the same algorithm.

I was under the impression web developers did not like this feature but that's based only on vague memories.

In my experience GitHub users rely on this behavior a lot, and always promptly report the bug when we break it. 😬

@caridy
Copy link

@caridy caridy commented Apr 29, 2019

cc @sfdciuie who raised the issue about compound controls during the F2F meeting last week. I think @tkent-google explanation makes sense, we should be fine with something like that.

@domenic domenic mentioned this issue May 6, 2019
3 of 3 tasks complete
@tkent-google
Copy link
Contributor

@tkent-google tkent-google commented May 7, 2019

Implicit submission

With whatwg/html#4187, manual implicit submission code would be:

let form = this.#internals.form;
// form.querySelector(':default') doesn't work due to 'form' content attribute.
for (let control of form.elements) {
  if (control.matches(':default')) {
    if (!control.matches(':disabled'))
      form.requestSubmit(control);
    return;
  }
}
form.requestSubmit();

Introducing a flag like this.#internals.submitImplicitly = true will eliminate the above code. IMO, it's a nice-to-have feature, and not a mandatory feature for the first version of form-associated custom element.

:default

We should be able to make a submit button with form-associated custom element. I just found a user agent needs to check if a form-associated custom element is a submit button or not to handle the :default pseudo class correctly. We need a flag like this.#internals.submitButton = true.

Autofocus

I proposed to move autofocus attribute to HTMLElement. whatwg/html#4563

@domenic
Copy link
Contributor

@domenic domenic commented May 7, 2019

First let met say that all of these things seem like they can be done on top of the current FACE (form-associated custom elements) pull request. That's a good sign :).

So I think there are two issues with implicit submission:

  1. Letting implicit submission work on a FACE, so that when you press Enter while focusing that FACE, it submits the form.
  2. Letting implicit submission click a FACE submit button, so that when you press Enter while focusing a normal input type=text, it clicks your FACE submit button.

With whatwg/html#4187, manual implicit submission code would be:

This is about (1), from what I can tell.

I think form.requestSubmit(control) should probably be control.click() to perfectly imitate the spec. ("must cause the user agent to fire a click event at that default button.")

But I also wonder, it seems like you'd need to add code like that to an keydown (keypress? keyup?) handler, and filter for the Enter key, right? That seems a bit fragile since it's assuming the Enter key is correct, but that's just prevailing convention... Maybe the missing piece is some kind of "requestimplicitsubmit" event, which gets fired on the Enter key or similar? Or a custom element callback??

I also think there's room for making this easier by adding a HTMLFormElement.prototype.defaultButton which would let you skip the loop.

In general I like the idea of people adding this manually, but doing it using platform-provided primitives that make it intuitive. So with all of my above it might be something like

this.addEventListener("requestimplicitsubmit", () => {
  const button = this.#internals.form.defaultButton;
  if (!button.disabled) {
    button.click();
  }
});

To reiterate, I am happy with these pieces being done after the initial version of FACE.

:default

This seems to start discussing (2). In particular I think this.#internals.submitButton = true should cause (2) to start working.

I also wonder about how this relates to #738 (comment) about allowing you to manually toggle states like :checked. (Did we open a dedicated issue for that, separate from :state()?) In particular, should we allow you to manually toggle :default? That seems necessary to get some of its other behaviors, like for <option selected> and <input type=checkbox checked>. But manual toggling seems in conflict with deriving it from internals.submitButton.

I've honestly never seen anyone use :default before your code example today so I am not sure how high priority this is. And especially unsure how high priority it is to support it for the non-button cases. But it's worth thinking about.

@tkent-google
Copy link
Contributor

@tkent-google tkent-google commented May 8, 2019

First let met say that all of these things seem like they can be done on top of the current FACE (form-associated custom elements) pull request. That's a good sign :).

I also think so. We don't need incompatible changes against whatwg/html#4383 in order to resolve known issues.

So, we, Chromium project, would like to start shipping process of both of event-based participation and form-associated custom element early next week. Does anyone still want to review these APIs?

domenic added a commit to web-platform-tests/wpt that referenced this issue May 16, 2019
domenic added a commit to tkent-google/html that referenced this issue May 16, 2019
domenic added a commit to whatwg/html that referenced this issue May 16, 2019
domenic added a commit to web-platform-tests/wpt that referenced this issue May 16, 2019
This is for WICG/webcomponents#187.

Specification PR: whatwg/html#4383.
@domenic
Copy link
Contributor

@domenic domenic commented May 16, 2019

Thanks everyone who accompanied us on this four-year journey!! On top of the feature that just got merged into the HTML spec, we have the following follow-up issues to make custom elements EVEN MORE powerful and on par with built-in elements:

@tkent-google
Copy link
Contributor

@tkent-google tkent-google commented May 17, 2019

I added a section to the proposal document for a list of follow-up issues.
https://docs.google.com/document/d/1JO8puctCSpW-ZYGU8lF-h4FWRIDQNDVexzHoOQ2iQmY/edit?pli=1#heading=h.wz1kbybdmdqe

moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Jun 19, 2019
…ements', a=testonly

Automatic update from web-platform-tests
Add tests for form-associated custom elements

This is for WICG/webcomponents#187.

Specification PR: whatwg/html#4383.
--

wp5At-commits: 3ccd79e32ced5ddab58f52e79f982d2ebfc7f98c
wpt-pr: 15740
xeonchen pushed a commit to xeonchen/gecko that referenced this issue Jun 19, 2019
…ements', a=testonly

Automatic update from web-platform-tests
Add tests for form-associated custom elements

This is for WICG/webcomponents#187.

Specification PR: whatwg/html#4383.
--

wp5At-commits: 3ccd79e32ced5ddab58f52e79f982d2ebfc7f98c
wpt-pr: 15740
marcoscaceres pushed a commit to web-platform-tests/wpt that referenced this issue Jul 23, 2019
@j9t
Copy link

@j9t j9t commented Jan 13, 2020

I added a section to the proposal document for a list of follow-up issues.
https://docs.google.com/document/d/1JO8puctCSpW-ZYGU8lF-h4FWRIDQNDVexzHoOQ2iQmY/edit?pli=1#heading=h.wz1kbybdmdqe

@tkent-google, are you still looking for feedback on the doc here? Just two notes:

  1. Major: It seems Docs auto-invalidated many code samples (note, for example, the wrong quotes in const n = getAttribute(‘name’);).
  2. Minor: Typo in sentence fragment “e.g. Create”.
@dflorey
Copy link

@dflorey dflorey commented Apr 22, 2020

I'm trying to build a form-associated web component and I've been able to get the example up and running.
But I'm not sure how to implement custom validation:
Let's say want to build a material design textfield and want to make it a drop-in replacement for existing <input type="text"> tag.
When the user submits a form with my textfield in it I'd like to report the validation in a custom way (red text below the input) instead of using the default browser tooltip.
So I'd expect to be able to plug my custom reportValidation() method into the internals so that it will get called instead of the default impl.
Right now I just can set the validity on the internals which is the wrong way round.
The custom element knows how to report validity, especially when it comes to composed / compound fields.
So I'd expect something along these lines:

this.internals = this.attachInternals();
this.internals.reportValidity = myReportValidityFunction
this.internals.checkValidity = myCheckValidityFunction

or a number of callbacks like
formReportValidity()
or even better just
reportValidity()
etc.

It will be interesting to see how this will get implemented from the MWC team:
material-components/material-components-web-components#971

@tkent-google
Copy link
Contributor

@tkent-google tkent-google commented Apr 27, 2020

@dflorey ElementInternals is a helper for custom element authors, and browsers never call its methods internally.

Overriding reportValidity() is easy. We can just add our own reportValidity() to the custom element class. However, we have no ways to override interactive validation UI. It's an issue of not only form-associated custom elements, but also built-in form controls.
I recommend to file a new issue on https://github.com/whatwg/html/issues .

@dflorey
Copy link

@dflorey dflorey commented Apr 27, 2020

Not sure if I understand correctly.
When calling reportValidity() on a native input field it will display the error message using the built-in UI (e.g. error popup on Chrome).
In my custom element I'd implement reportValidity() in a way that matches the design guidelines (e.g. material design).
I'd assume that when submitting a form on a form-associated custom element my reportValidity() would be called instead of the built-in UI, but unfortunately this seems not to be the case.

In the given sample in the doc...

https://docs.google.com/document/d/1JO8puctCSpW-ZYGU8lF-h4FWRIDQNDVexzHoOQ2iQmY/edit?pli=1#heading=h.2izmbauztyja

....and in all other examples that I've found it is also a bit weird that the validity will be set whenever the input changes as this is may be a very expensive operation.
Think of a signature input fields that does all kinds of image analysis to check if the control is valid. So the validation should only be checked when the browser calls my checkValidity() or reportValidity() methods instead on each change of the input.

I'd also expect to have a formDataCallback(FormData) or something along those lines to add the contents of the custom element to the form data to be submitted.
Right now the only way is to call this.internals_.setFormValue('') to set the value, but when should I call this method? Whenever the value changes? Again this may take a lot of time to calculate the value based on the input, so I'd want to call this method only whenever the user submits the form. How to do that?
I tried to use the event based form participation:

https://docs.google.com/document/d/1JO8puctCSpW-ZYGU8lF-h4FWRIDQNDVexzHoOQ2iQmY/edit?pli=1#heading=h.je8c7y5qpgki

but this seems not to work (quite yet)?

It would be so cool to be able to implement a custom element that can be used as a drop-in replacement for native input fields or to add new exciting input controls, but right now I don't see a way to do so due to the issues above.
Hopefully I just got it all wrong. I'd be super-happy to find a code example that shows a basic example how to

  • add the value to the formdata on form submission
  • performs the validation check when the form gets validated (=user clicks on submit)
  • reports an error in a custom way and avoids the default browser UI
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.