Add an event for when a user attempts to submit
What problem are you trying to solve?
I have components which have the concept of a "Server Error" and a "Client Error".
Server Error's do not affect a Form Associated Custom Elements validity, but should get cleared when a user attempts to submit a form, either by calling requestSubmit() or by a user clicking a <button type="submit">
What solutions exist today?
Patching HTMLFormElement.prototype.requestSubmit and emitting an event like "request-submit" and then having a root node click listener looking for submit buttons:
this.rootNode().addEventListener("click", (e) => {
const submitter = e.target.closest("[type='submit']")
if (submitter) {
e.dispatchEvent(new Event("request-submit", { bubbles: true, composed: false, cancelable: true }))
}
})
submit event issues
form.addEventListener("submit") will never fire if the form is invalid.
invalid event issues
form.addEventListener("invalid", () => {}, {capture: true}) has multiple problems.
1.) It does not check for elements that were invalid outside of the form IE:
<form id="my-form"></form>
<input form="my-form" required>
Will never trigger the "invalid" event for the form to capture.
2.) "invalid" does not account for if it was triggered by reportValidity(), checkValidity(), requestSubmit(), or clicking a submit button.
formdata event issues
Form data can be triggered by anything such as new FormData(form) and doesn't tell you how it was triggered, as far as I know.
How would you solve it?
I would like to solve it by having a "requestsubmit", "attemptsubmit", or similar event fired regardless of the validity of the form and it would fire whenever you call requestSubmit() or when a submit button attached to the form is clicked, or if the user hits Enter inside of an input.
Anything else?
Not that I can think of. I hope im not missing something obvious here.
Problem 1:
const originalRequestSubmit = HTMLFormElement.prototype.requestSubmit;
HTMLFormElement.prototype.requestSubmit = function(submitter) {
this.dispatchEvent(new Event('attemptsubmit', { bubbles: true, cancelable: true }));
originalRequestSubmit.call(this, submitter);
};
document.addEventListener('click', (e) => {
const submitter = e.target.closest("[type='submit']");
if (submitter && submitter.form) {
submitter.form.dispatchEvent(new Event('attemptsubmit', { bubbles: true, cancelable: true }));
}
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && e.target.form) {
e.target.form.dispatchEvent(new Event('attemptsubmit', { bubbles: true, cancelable: true }));
}
});
Problem 2:
document.querySelector('form').addEventListener('attemptsubmit', (e) => {
console.log('Form submission attempted, clearing server errors');
});
One (workaround?) for this is to put names/values on the submit inputs, and then they'll appear in the formdata event only if the form was specifically submitted. But I concede that this is really implicit.
One (workaround?) for this is to put names/values on the submit inputs, and then they'll appear in the
formdataevent only if the form was specifically submitted. But I concede that this is really implicit.
Except in a component library you can't really control this :/
Why can't you use the click event on the submit button?
Someone claimed this does not work during WHATNOT, but it does:
https://software.hixie.ch/utilities/js/live-dom-viewer/?%3Ciframe%20name%3Diframe%3E%3C%2Fiframe%3E%0A%3Cform%20action%3D%2F%20target%3Diframe%3E%0A%3Cinput%20name%3Dtest%3E%0A%3Cinput%20required%20name%3Dtest2%3E%0A%3Cinput%20type%3Dsubmit%20onclick%3Dalert(1)%3E%0A%3C%2Fform%3E
It doesn't work when calling .submit() or .requestSubmit().
Why can't you use the
clickevent on the submit button?Someone claimed this does not work during WHATNOT, but it does:
https://software.hixie.ch/utilities/js/live-dom-viewer/?%3Ciframe%20name%3Diframe%3E%3C%2Fiframe%3E%0A%3Cform%20action%3D%2F%20target%3Diframe%3E%0A%3Cinput%20name%3Dtest%3E%0A%3Cinput%20required%20name%3Dtest2%3E%0A%3Cinput%20type%3Dsubmit%20onclick%3Dalert(1)%3E%0A%3C%2Fform%3E
Yup, thats the current workaround I suggested, but as @keithamus pointed out, it wont work with requestSubmit(). submit() is naturally an odd edge case and I wouldn't expect that to work. But as for requestSubmit(), I really don't want to mess around with patching the HTMLFormElement prototype.
Maybe a new property on FormDataEvent could be added to indicate that it was initiated from requestSubmit() or user submit.
Maybe a new property on
FormDataEventcould be added to indicate that it was initiated fromrequestSubmit()or user submit.
If we add a new property to FormDataEvent it should indicate whether it was initiated from new FormData(form) or from form submission (be it requestSubmit or user submitting). It's probably a way to go about it that could be made to work, though it feels a bit implicit compares to something like form.onrequestsubmit.