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'),
...
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
.