Reputation: 11994
In Formik, I need validation errors to be displayed in both cases:
(1) is working but (2) is not. When I come to the form and just click the Submit button, nothing happens and the errors aren't displayed. The errors only get displayed when I touch the controls.
I think the problem is that to satisfy (1), my controls have
isInvalid={touched.startDate && errors.startDate}
But when I click Submit immediately, the control hasn't been touched yet, so this isInvalid
condition fails. But I can't remove the touched.startDate
part because otherwise, all invalid controls always start showing when filling out the form -- even the ones I haven't been touched. I need to keep my touched
requirement when filling out, but also show all errors on Submit. The Submit is the one case where all errors have to be shown at once. Is it possible to pass some submitClicked
variable somewhere to achieve this?
<Formik enableReinitialize
validationSchema={schema}
onSubmit={ (values, { validate }) => {
alert(JSON.stringify(values, null, 2));
}}
initialValues={{}}
>
{({
handleSubmit,
handleChange,
handleBlur,
values,
touched,
isValid,
errors,
}) => (
<Form onSubmit={handleSubmit}>
...
{/* EXAMPLE */}
<Form.Control type="date"
name="expirationDate"
value={values.expirationDate}
onChange={handleChange}
onBlur={handleBlur}
isInvalid={touched.expirationDate && errors.expirationDate}
</Form.Control>
</Form>
...
// Yup Schema used for form validation
const schema = yup.object().shape({
expirationDate: yup.date().required('Expiration Date is required'),
frequencyDays: yup.number().required('Frequency is required'),
interval: yup.string().required('Frequency interval is required'),
...
Upvotes: 2
Views: 4636
Reputation: 39
This problem is happening in my app due to api call and showing inputs
initialValues={{
...data?.data,
primary_android: data?.data
? data?.data.primary_android
: 'Art & Design',
keyword_android: data?.data?.keyword_android
? JSON.parse(data.data.keyword_android)
: [],
keyword_ios: data?.data?.keyword_ios
? JSON.parse(data.data.keyword_ios)
: [],
primary_iso: data?.data ? data?.data.primary_iso : 'Art & Design',
secoundry_iso: data?.data ? data?.data.secoundry_iso : 'Books',
liveStatus: 'pending'
}}
as you can see the fields which is type manually primary_android,keyword_android,keyword_ios etc are valid for errors when I click on submit but other fields ...data?.data
which are fetching and showing are not be valid for onBlur error when submit so
So the simple answer is if you are using api call for inputs initial data make sure you add every property statically and the problem will be fixed
Upvotes: 1
Reputation: 11994
Since a lot of people are viewing this thread, here's what we've ended up with. This is our React Bootstrap control example, in this case a Select called frequencyDays
inside a Formik. Note the following:
isInvalid={(submitClicked && errors.frequencyDays) ||
(!submitClicked && touched.frequencyDays && errors.frequencyDays)}
This means that either (1) Submit was clicked and errors exist, or (2) Submit was NOT clicked, but this control was touched, and errors exist.
<Form.Control as="select"
id="dropdownFrequencyDays"
name="frequencyDays"
value={values.frequencyDays}
onChange={handleChange}
onBlur={handleBlur}
isInvalid={(submitClicked && errors.frequencyDays) || (!submitClicked && touched.frequencyDays && errors.frequencyDays)}
SubmitClicked is a variable, initialized/set as follows:
// Shows whether the Submit button was clicked (used to show all form validation errors at once)
// initially FALSE
const [submitClicked, setSubmitClicked] = useState(false);
set in Submit Button's onClick:
<Button type="submit" disabled={isSubmitting}
onClick={() => {
setSubmitClicked(true); // We set it to TRUE in Submit's onClick
}}
variant="primary">Submit</Button>
If you're using Material UI, it's similar to React-Bootstrap and it has some error
property on its controls which is analogous to isInvalid
.
Upvotes: 1
Reputation: 834
I think you're right that because you have the check to see if a field is touched
, the errors aren't rendering after validation. I think a workaround to this could be to programmatically set the state for all fields to touched=true
once the onSubmit handler is called.
form.setTouched({...form.touched,[field.name]: true });
There isn't a codesandbox to go off of but something like this
<Formik enableReinitialize
validationSchema={schema}
onSubmit={ (values, { validate }) => {
// Set the form fields to touched programmatically
form.setTouched({...form.touched,[field.name]: true });
alert(JSON.stringify(values, null, 2));
}}
initialValues={{}}
>
{({
handleSubmit,
handleChange,
handleBlur,
values,
touched,
isValid,
errors,
}) => (
<Form onSubmit={handleSubmit}>
...
{/* EXAMPLE */}
<Form.Control type="date"
name="expirationDate"
value={values.expirationDate}
onChange={handleChange}
onBlur={handleBlur}
isInvalid={touched.expirationDate && errors.expirationDate}
</Form.Control>
</Form>
Upvotes: 2