Open orenklein opened 6 years ago
We could prototype this with a special version of Field. The tougher bit is how to do it without Yup.
Open to PRs. Also FYI/reference, unlike Field, FastField tries to run validation synchronously before running it async. Perhaps that technique should be moved as the default
For the general case, it seems like just passing fieldName
to validate
is "good enough" to let someone handle that if they want. You can implement validationSchema in terms of that api for single field validations. It's not particularly hard to do with yup, react-formal
implements it like this: https://github.com/jquense/react-formal/blob/master/src/Form.js#L368-L383
Interesting. Will check this out.
Any updates on this? Otherwise I would give @jquense idea of passing the fieldName
to validate
a shot if you don't mind.
EDIT:
Nevermind. Since we are only doing client side validation before the submit, touched.email && errors.email
is totally working for me. So I am only displaying the errors when the fields have been touched. Of course that is not solving the issue with server side validation. Sorry for making noise here.
Any solutions?
test
method of yup schema invokes even change some other field. It's very inconvenient.
You can pass a validate function to Field
-- Jared
From: Serhey Shmyg notifications@github.com Sent: Thursday, June 28, 2018 6:02:19 AM To: jaredpalmer/formik Cc: Jared Palmer; Comment Subject: Re: [jaredpalmer/formik] Validate only one field at a time (#512)
Any solutions?
— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/jaredpalmer/formik/issues/512#issuecomment-400982758, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AD30G-ezC6vwgwBIxMYA3GWXf643lt0Tks5uBKmrgaJpZM4SpEE_.
@jaredpalmer Can you provide more details, please?
I don't use Field
component from formik.
Oh, you mean I don't need .test
in yup schema and just validate in every require field separately?
Validate all schema onChange, it's very bad solution.
See 1.0.0-beta.3 Field validate.
I think it's not an option use some Field component.
Question was about yup.test
validation.
You should warn in readme than about using yup.
test
and 'transform' doesn't work as expected.
feel free to submit a PR.
You can always use the normal validate
function instead of validationSchema
and then use Yup to to get the functionality you need.
@jaredpalmer if I pass validate
function to my Field components, it runs all these functions when I edit only one field, ON EVERY SINGLE KEYSTROKE. Why? It's not obvious. I don't want to use Yup. Is there a possibility to disable this behaviour and run one validate function?
Would also like a solution to this, my scenario we query a pay as you go api for validation and this would call it over and over with the same value unless we intervene.
@idesignpixels Same problem, check user or some other API call will lead to error 503 (Service Unavailable)
@suberg @idesignpixels let me make sure I am understanding the suggested behavior:
validationSchema
validate
validate
value
is first argument@jaredpalmer let's say we have username
and email
fields. We set our validation schema to
yup.object().shape({
email: yup.string().required().email()
}}
Then we pass a custom validation function as validate prop to the username Field that validates if our username is unique. What is happening is that when I type at the email field, the validate function provided to the username field is also running.
Hola! So here's the deal, between open source and my day job and life and what not, I have a lot to manage, so I use a GitHub bot to automate a few things here and there. This particular GitHub bot is going to mark this as stale because it has not had recent activity for a while. It will be closed if no further activity occurs in a few days. Do not take this personally--seriously--this is a completely automated action. If this is a mistake, just make a comment, DM me, send a carrier pidgeon, or a smoke signal.
ProBot automatically closed this due to inactivity. Holler if this is a mistake, and we'll re-open it.
I'm trying to do async validation using Field's validate
and the async call to the server (to check if the email already exists or not) fires for any change in other fields in the form. This is not a great UX.
It'd be great to expose the fieldName to validate
on Field so that at least I can check for which field is updating and prevent firing the async call unless it was the field being updated.
I think I have an ok solution for people using <Formik />
and normal input fields
// Custom function to validate single field in validationSchema
validateSingle = (key, formProps) => {
validationSchema.validateAt(key, formProps.values).then(() => {
formProps.setFieldError(key, '')
}).catch(error => {
formProps.setFieldError(key, error.message)
})
}
Edit: Updated code...
Calling this onBlur should only update the single error field and run the single validation Just pass in the name of the field and the formProps
Question @jaredpalmer, are you saying current the current expected behavior for validate
on Field components should only run when that specific field is touched? I am using only Field-level validate props with Formik v1.5.1, but I'm also still seeing all validations re-running on change and blur.
I think it makes sense to
validate
is specified on Field
componentvalidate
is specified, be it Field
or Formik
component@jaredpalmer what do you think?
Is there built in way to run only single field validation on change/blur?
@jaredpalmer has stated that "However Formik supports Field-level validation now, which does only run one-at-a-time."
but I'm unable to find any examples and for me all the <Field>
s run their validation functions on any field change/blur.
I had the same problem as others here, Formik set up with Yup and validationSchema
, and a test
async validation that was repeated for each keystroke, on other fields too.
I worked this around by invoking my remote validation onBlur
:
onBlur={(e) => {
handleBlur(e);
$.get('/api/validations/companyName', { value: e.target.value }).then(response => {
companyNameUnique = response.success;
validateForm();
});
}}
I stored the result of validation in a module variable (companyNameUnique
) and then forced immediately a full form validation.
This way I can have a sync test in Yup that's simply using the cached result:
companyName: yup.string()
.test('companyNameUnique', l.companyNameUnique, () => companyNameUnique),
I'm running into the same issue, where all the fields that have been touched are validated onChange and onBlur on any field.
I'm using the validate
on the Field
with name
prop set.
return (
<Field
name={name}
validate={validateFn}
render={({ field, form }) => (
<CustomField
className={className}
childNode={children}
displayError={displayError}
label={label}
labelClassName={labelClassName}
meta={{ error: form.errors[field.name], touched: form.touched[field.name] }}
required={required}
/>
)}
/>
)
validateFn is an async function
From what I could check in the formik code, the validators run for the entire formik state (which is set on touched, on blur and on change). Instead of running it on the entire state, would it make sense to just run it for the field only instead ?
https://github.com/jaredpalmer/formik/blob/master/src/Formik.tsx#L129
Besides on submission, what was the use case to always validate all the fields ? 🤔
I've digged a bit into the docs and code and manage to figure one workaround for single field validation. It seems to be pretty hardcoded to always validate all fields set in state (and touched) in the current implementation so might be tricky to come up with a solution that doesn't involve a prop like validateOnField
in the Formik
component. Would that be a reasonable solution ?
Anyway, start by disabling form level validation onChange and onBlur
<Formik
....
validateOnChange={false}
validateOnBlur={false}
>
This will avoid all field validations but will still set the values in the state (plus touched state)
There's an exposed prop called validateField
that performs that single field validation once
const onInputBlur = (event, field) => {
handleBlur(event)
validateField(field)
}
validateField
will handle setting the error in the formik state. So we do the formik handleBlur
to set value and touched in state and then call the field validation with the field name.
This way also keeps the full validation on submit (by default).
@jaredpalmer do you think it's a reasonable workaround ? Haven't tested it fully but so far it's been avoiding API validation calls on certain fields (my goal). Maybe I'm missing some case that I haven't thought of.
@pedroabreu it could be a workaround; But just for people that use field level
validation.
If you are using validationSchema
and yup
the validateField
function is not an option.
This behaviour of validating fields one by one is very much needed and it should have been the default from the beginning.
At least we should start giving an option for opting out specific fields to be validated in case other fields are changed.
Then trigger validation for that specific field only when interacting with it.
Does anyone have a good workaround for this?!
@pedroabreu
You state
There's an exposed prop called
validateField
that performs that single field validation once
What do you mean by this? Where is that prop exposed?
In the Formik
component at least. Here it is as part of an example for single field validation
@asgeirfri
Based on some experiences with Yup last week, your method will not work when you have Yup schemas that contains when(), and it depends of others, you need to send contexts etc... a problem.
Any updates? I see this issue has gone stale...
i've have a workaround incase anyone is still interested in this.
` <Form.Field error={errors.valueName && touched.valueName !== undefined ? true: false}>
<Input
value={values.valueName}
name="valueName"
error={errors.valueName && touched.valueName !== undefined ? true: false}
onChange={handleChange}
onBlur={handleBlur}
/>
{errors.valueName && touched.valueName && <ErrorLabel
children{errors.valueName}/>}
</Form.Field> `
@pedroabreu I agree but it looks like that would produce a new issue due to a race condition, in my case it seems to be referencing prevState when using onChange handler instead of onBlur
@jaredpalmer and @pedroabreu the better workaround would be using custom onChange handler with setFieldValue('borrower_additional', e.target.value, true) which would trigger validation correctly but it looks like using true there does not matter if validateOnChange is false. This seems to be the biggest problem w/Formik because I like others don't use a validation schema and don't need the whole visible form to validate on every single change
@pedroabreu avoid the race condi w/
onChange={async e => {
await handleChange(e)
validateField('borrower_additional')
}}
@cigzigwon I've just spend several hours trying to figure out why was the value validated first and only after set in the state. I already had a codesandbox example to open an issue 😅
For time travelers from the future:
handleChange
will trigger an internal state change, which by nature is async setState
validateField
is called, it will run against the old state value 🏎 It's weird that I didn't ran into that when on onBlur
but only now on the onChange
. I'll update the other post I made
Any new updates on this one? 😄
If you are having an issue like the latter then you should probably disable validation, events w/false and do field level validation. Ive advised that the recent workaround works just fine as indicated above. Formik will still validate all fields onSubmit
Hi guys, i've recently started using formik and now my problem is that when 1 field being changed validation goes on whole form fields so all errors appear at props and my main question is there any solution for this? Formik is really popular, but i didn't find anything in documentation about this.
@ops1ops Just use some other lib.
@ops1ops errors should not appear on the form because the error message component provided by Formik checks to see if a field has been touched (formikProps.touched.myFieldName
). If you're using your own message display, you should also check the touched
property to only display errors when it is true. Here's an example:
<Formik
initialValues={getInitialValues()}
validationSchema={getValidationSchema()}
>
{formikProps => (
<Form>
<div>
<Field name="myField" required />
{
formikProps.touched.myField &&
formikProps.errors.myField &&
<p>{formikProps.errors.myField}</p>
}
// or
<ErrorMessage name="myField" />
</div>
</Form>
)}
</Formik>
This is documented here: https://jaredpalmer.com/formik/docs/api/errormessage
@johnrom thanks for your answer. This is good example, but not really what i need. Currently i have to validate fields onChange, so if i use touched prop i cant really do it, because onChange validation will work only when field was touched. The solution i found is to make your own onChange handler using setFieldValue with setFieldTouched. And now i'm stuck with problem that formik updates all errors when you change field with setFieldValue.
@ops1ops a field is marked as touched after its first change if you use the API provided by formik. if you use setFieldValue
, this might not be the case (code is not in front of me). But it is if you use handleChange
. Formik will update all errors when you change a field with setFieldValue, but they will not display on a field until that field is both touched and invalid. If your issue is that there is a performance concern from changing all of the errors, I can understand that. If, however, your issue is that all of the errors will display at once on fields a user hasn't filled out yet, they should not if it is hooked up normally.
@johnrom
a field is marked as touched after its first change if you use the API provided by formik.
are you sure about this? For example:
<Form.Item
validateStatus={touched.name && errors.name ? 'error' : 'success'}
hasFeedback={touched.name || values.name}
help={touched.name && errors.name}
>
<input
placeholder="name"
name="name"
// onChange={ (a) => {
// setFieldValue([a.target.name], a.target.value);
// setFieldTouched(a.target.name)
// }}
onChange={handleChange}
onBlur={handleBlur}
/>
</Form.Item>
Because even with this default input when you focus it and start changing, errors still dont appear because touched.name is not true. But when you leave input, touched.name becomes true and errors appear. Maybe i don't know something, i've already said that i'm new with formik
@ops1ops sorry I misspoke, it doesn't set touched until after the field is blurred. This is the default behavior in many forms so that the user is not presented with errors before they've had a chance to finish typing.
@johnrom so i was just interested is there anything in formik that provides onChange validation without being blurred. I managed this workaround
// onChange={ (a) => {
// setFieldValue([a.target.name], a.target.value);
// setFieldTouched(a.target.name)
// }}
but i now i have another problems because of it. Maybe you or someone know better workaround
@ops1ops that's a slightly different topic than this issue, feel free to open a separate issue or join the discord to ask your question. if you open an issue please use the Bug Report
template as it has information regarding creating a sandbox and filling out your Formik version information.
@johnrom ok, thanks for all
Bug, Feature, or Question?
Feature/Question
Current Behavior
Currently, validation is running asynchronously on the whole schema (assuming you use ValidationSchema of yup). It is reasonable to run the validation on submit, however, It is extremely cumbersome to run it on every field change/blur.
Especially if you have some backend validation (using yup.test). Assuming you have a couple of fields, field A, and field B - the later must go through backend validation. Every time you change field A, the validation runs both on A and B which will cause unnecessary backend calls.
I also tried using the new alpha version's handleChange('fieldName') but I still experience the same behavior.
Suggested Solutions
Using yup schema, using yup.reach seems reasonable, even though I'm not sure how is its performance (https://github.com/jaredpalmer/formik/issues/35)
Formik validate function - pass the event's field name. It will allow the developer to validate only one field at a time.
Environment