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

Form valid event issued when elements are invalid. #92

Open
GeoffCapper opened this issue Mar 26, 2020 · 4 comments
Open

Form valid event issued when elements are invalid. #92

GeoffCapper opened this issue Mar 26, 2020 · 4 comments
Labels
documentation Not a bug, but behaviour needs better documentation

Comments

@GeoffCapper
Copy link

I'm trying to use Hyperform to detect when the form switches between an invalid and valid state so I can switch disabling of the submit button.

If I monitor the "valid" event on the form it keeps getting triggered even though elements within the form are still invalid.

If I run form.checkValidity() on startup each field will indicate an "invalid" event and checkValidity returns false. It seems calling "checkValidity" on the form won't trigger any event on the form (validate, invalid or valid).

I've got a test with three required text fields and a submit button. If I tab through the fields they each report "invalid" events, but nothing at the form level. Once I reach the submit button the form reports a "valid" event (when it should really be "invalid").

Test, if it helps, is at: https://codepen.io/GeoffCapper/pen/eYNQWYr

When I click submit the form issues a "validate" event, and each field in turn issues an "invalid" event followed by the form issuing an "invalid" event. Once all the fields have been checked the form then issues a "valid" event.

Are the form-level "valid"/"invalid" events broken, or are they for some other purpose than I'm thinking?

Thanks,
Geoff

@Boldewyn
Copy link
Contributor

Hi Geoff,

thank you for the feedback! I see the problem, but unfortunately that’s based on a misconception. The valid/invalid events are strictly per-element events. You see in the console, that each Field ... issued INVALID event is immediately followed by a separate Form has INVALID event. That is due to the events bubbling up through the DOM and eventually reaching their parent <form>.

There is indeed a non-standard form-level event forminvalid, that’s issued directly on the form, if any of its children proved invalid during a submit (*). The submit event takes the role of a corresponding formvalid event, since it’s only reached, iff all elements are valid.

So, long story short, where does the valid event come from? Well, as Yoda said once, “There is another”. There’s indeed a fourth element, that needs to be validated due to the specification: the humble submit button.

I hope, this explanation makes some sense. I’m keeping the issue open for now, because that’s definitively something I should document better.

(*) not for methods like form.checkValidity() though. That’s on purpose. In the submit case, an author wouldn’t have a comfortable possibility to react to an invalid form apart from registering to invalid events, which may also be triggered by other means. In the “call a method” case, we’re already in author code, that can directly react to the outcome of the called method.

@Boldewyn Boldewyn added the documentation Not a bug, but behaviour needs better documentation label Mar 26, 2020
@GeoffCapper
Copy link
Author

Thanks for clearing that up @Boldewyn, I appreciate the detailed explanation.

In order to do what I want would I be best just calling form.checkValidity() every time a form field changes and using the return value, or is there some internal registry or field inside the hyperform I could tap into? I know I could use my own eyes, but I'm hoping your knowledge could point me in the right direction to start :-) Cheers!

@Boldewyn
Copy link
Contributor

Boldewyn commented Mar 26, 2020

Let’s see... No, there is no internal bookkeeping of the state of single input elements, but you could create that quickly yourself (ES6 needed, though):

// assuming `form` to be a reference to your form element
var element_states = new Map(Array.from(form.elements).map(e => [e, e.validity.valid]));

If an element changes state, you can update the map, thanks to event bubbling, from the form element:

form.addEventListener('invalid', event => {
  element_states.set(event.target, false);
});
form.addEventListener('valid', event => {
  element_states.set(event.target, true);
});

And to check, if all elements are valid, you could do something like

var valid = Array.from(element_states).map(item => item[1]).every(i => i);

The solution will become a bit more complicated, if you add/remove elements dynamically. For that case you could use a MutationObserver in quite the same way as Hyperform does here: https://github.com/hyperform/hyperform/blob/master/src/components/setup.js#L146-L163 and dynamically add and remove entries from element_states.

@GeoffCapper
Copy link
Author

Thanks @Boldewyn / Manuel, couldn't have asked for a better head start on it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Not a bug, but behaviour needs better documentation
Projects
None yet
Development

No branches or pull requests

2 participants