html icon indicating copy to clipboard operation
html copied to clipboard

Add an event for when a user attempts to submit

Open KonnorRogers opened this issue 1 year ago • 1 comments

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.

KonnorRogers avatar Oct 11 '24 22:10 KonnorRogers

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');

});

abnahid avatar Oct 13 '24 20:10 abnahid

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.

noamr avatar Oct 24 '24 16:10 noamr

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.

Except in a component library you can't really control this :/

KonnorRogers avatar Oct 24 '24 22:10 KonnorRogers

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

annevk avatar Oct 25 '24 11:10 annevk

It doesn't work when calling .submit() or .requestSubmit().

keithamus avatar Oct 25 '24 13:10 keithamus

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

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.

KonnorRogers avatar Oct 25 '24 14:10 KonnorRogers

Maybe a new property on FormDataEvent could be added to indicate that it was initiated from requestSubmit() or user submit.

zcorpan avatar Nov 04 '24 16:11 zcorpan

Maybe a new property on FormDataEvent could be added to indicate that it was initiated from requestSubmit() 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.

noamr avatar Nov 04 '24 16:11 noamr