If true, validation will happen on blur. If false, validation will happen on change. Defaults to false.
I would suggest adding another config option;
validateOnChange: bool
validateOnBlur: bool
I'm considering abandoning my own attempt at a form library (it was a great learning experience though), since you certainly know more about the different pain points users have, and the internal workings of React and how to properly do performant libraries, considering your background with forms and React.
One thing I really liked with my solution was the ability to do sync validation onChange, and async (i.e network requests) on onBlur.
I haven't figured out another way to do this just yet. But If we can have the library to validate on both onChange and onBlur this would be possible.
Not sure why this makes sense. What does { validateOnBlur: true, validateOnChange: true }, or the false false equivalent, even mean? If you're validating on change, doing so on blur is meaningless, right?
If you look at your example here, the verifyUsername function is hit on every keystroke (if the sync rules passes)
https://codesandbox.io/s/kl9n295n5
What I essentially want to do is to create a validate function that checks whether the field is currently active, if it is, I can disregard my async rules and only run the sync rules. When it's not active, but the validation triggers, it is blurred, and I can run my async rules if no sync errors exists.
To do this, I also need the FormState in the validate function. Right now I'm using a reference to get it. But I was thinking of opening another issue depending on your response to this one.
{ validateOnBlur: true, validateOnChange: true } means simply run on both onBlur and onChange.
{ validateOnBlur: false, validateOnChange: false } would disable the validation.
Just to demonstrate my point a bit better, I put together a simple example here:
https://codesandbox.io/s/jn1lwj06lv
The sync validation (required check) vill run on onChange, but the the async validation verifyUsername will not fire until you leave the field.
Wow, @Zn4rK, that's some impressive FormSpy hacking to get on-blur validation almost-working.
@erikras Wow! This looks promising, I think I'll be able to use this!
I had a feeling it would be possible with FormSpy, but I did not have that much time to figure out how it all fit together when I created this issue.
IMO this issue is resolved with the above example...
A little update on this issue;
I've been experimenting with this for a few hours today, and initially I thought it would work great. Don't get me wrong, it does work great and I can probably still use it - but lifting parts or all validation responsibility from the library introduces another set of issues;
We have no way of knowing if the form is done validating in onSubmit() (edit: this was bad phrasing on my part, we can of course read the "validating"-props in onSubmit, and I guess we could subscribe to changes to "data" to verify that the validation is done). Just disabling the button and waiting for the form to validate it self is not good UX - we could build a promise based solution in OnBlurValidation, but that's something that the library already does when using the "normal" validations.
If a user submits the form our extra layer of validation will not be run in the current example. We'll have to build something that triggers all extra validation when the form is submitted. Try it - insert anything in the "lastName" field to make the form not be pristine, and then submit.
I only have loose thoughts on how we could go about resolving these issues (or the original one).
I've almost managed to hack up a solution using a <FormSpy /> to detect changes to active fields to trigger a validation using a mutator (which in turn does nothing, but mutators always triggers the validation), and then using a <Field /> to add a field-level validator the reads the current reactFinalForm.getState() via context. It's ugly, and I was mostly curious of what it would take to make it work.
The only issue with this is that the mutators always trigger the validations so if I want to set some field data in the validate (loading indicator) I get a recursive loop. I could use reactFinalForm.pauseValidation() since I'm already using the context, but then I'm introducing a race condition - another field might not validate.
My thoughts I had while I was hacking this^ up was;
FieldState should have a validating property.FormStaterunValidation() via FormRenderProps. I'll end this update in some pseduo code:
<Form
render={(formRenderProps) => {
<React.Fragment>
{/* Other stuff */}
<Field
name={name}
// It would probably be awesome to have FieldState here as well...
validate={(value, values, FormState) => {
// Normal sync validation
if(!value) {
return 'This field is required';
}
// Check if we can run async validation
if(FormState.active === undefined) {
return new Promise(resolve => {
setTimeout(() => {
if(value === 'admin') {
resolve('No way!');
}
resolve();
}, 2000);
})
}
}}
/>
{/* Other stuff */}
<FormSpy
subscription={{ active: true }}
onChange={({ active }) => {
const { active: previouslyActiveField } = formRenderProps;
if (active === undefined && previouslyActiveField !== undefined) {
// A blur occured, run the validation for the previously active field
formRenderProps.validate(previouslyActiveField);
}
}}
/>
</React.Fragment>
}}
/>
Hopefully my thoughts here makes sense. If they do, we can extract some of them to new issues...
I'm re-opening this to facilitate the discussion. Feel free to close it if we should take the discussion somewhere else :)
@erikras I think this issue is not actionable without your decisions regarding those newly proposed features.
If you ask me, the idea seems to make sense. It's important to figure out an intuitive API for it.
My 2c: I think validateOnBlur should not disable validateOnChange. Here is one example why. I'm triggering form submission on mouse down on a save button, and that doesn't blur the currently active field, so the form is submitted even though the validation doesn't pass.
Why do I use onMouseDown instead of just onClick? That's because I display the errors from the validation under the inputs. When there are errors at submission, the save button is pushed down, sometimes way inder the current mouse pointer, and this cancels the click event.
A possibly related behaviour I quite like is having "onBlur" validation initially, and after the initial blur, validation is done onChange.
Most helpful comment
@erikras I think this issue is not actionable without your decisions regarding those newly proposed features.
If you ask me, the idea seems to make sense. It's important to figure out an intuitive API for it.