React-Datepicker with Formik and Yup: Date value not validated on first blur, other than .required()
Asked Answered
I

3

3

I'm using React-Datepicker inside a Formik form validated with Yup. To integrate React-Datepicker inside Formik I used the wrapper solution in this thread.

When a value is initially entered, .required() gets checked, but any other validation does not get checked. So I'm not getting my StartDate later than today validation right away. These other validations do get triggered if I re-enter the control a second time and exit it. So the only initial validation error that happens immediately is .required(), but for any other errors I need to re-touch the control. Are there any solutions to this?

EDIT: I noticed that Formik's .touched does not get set on the 1st DatePicker input. It only gets set on subsequent touches/inputs.

Yup

startDate: yup.date().nullable().required('Start Date is required')
                                .min(new Date(), 'Start Date must be later than today'),

DatePicker Wrapper -see this thread - credit to ToolmakerStever

I tried adding onCalendarClose to force re-validation per this DatePicker issue report, and it indeed may be happening, but this could also be a Yup Schema issue -- I'm not sure.

const { setFieldValue, validateField, values, handleBlur } = useFormikContext();

   return (
        <DatePicker
            {...field} 
            {...props} 
            showMonthDropdown
            showYearDropdown            
            selected={(field.value && new Date(field.value)) || null}
            onChange={val => {
                setFieldValue(field.name, val);
            }}
            onCalendarClose={val => {
                // Force-validate onCalendarClose to avoid any potential DatePicker Blur issues
                // Didn't help
                validateField(props.name);
            }} 
            onBlur={e => {
                // Call Formik's handleBlur
                // Didn't help
                handleBlur(e);
            }}           
          
        />

    )
Inhale answered 23/5, 2021 at 17:51 Comment(1)
can you create a sandbox and share . It will be easier to debug and help .Sirkin
I
4

I found a fix. Something wasn't marking the DatePicker as touched the first time. DatePicker exposes an event called onChangeRaw where I force-touched the control. Now all errors are triggered right away without re-touching.

        onChangeRaw={e => {
            setFieldTouched(field.name, true, true);
        }}

This goes inside the DatePicker Wrapper for Formik, as shown in this post.

React-Datepicker has a bug with Blur for some reason, documented here. Their Blur recommendations include calling onCalendarClose or onChangeRaw. But only onChangeRaw worked reliably for me.

Inhale answered 23/5, 2021 at 18:24 Comment(1)
In my case, I misspelled the name of the field in Yup object (it was different than in initialValues object.)Kinzer
S
1

Creating a wrapper with Field works fine . The validations are getting triggered without any issues. Here is the sandbox.

Formik DatePicker Example

Sirkin answered 23/5, 2021 at 18:29 Comment(5)
Yes, but you only tested the errors attribute. The problem was the touched attribute. On first input, the touched was not getting set. You had to refocus the control and only then would get the correct touched behavior. My Formik error depends on both errors and touched to display an error.Inhale
Formik by default will trigger a validation if the field is touched. In the sandbox which i have shared . You can just click on the input field and click outside you can see the touched attribute getting populated .Sirkin
No, in your sandbox if I click 'May 5, 2021", the touched on this control is not set the first time after making a selection and closing the calendar. That should already make it touched, I shouldn't need to additionally click outside again. But if you re-focus the control then it will get set. That's the DatePicker Blur bug. I show my error message in a custom way depending on both error and touched, so that's how I ran into this bug. touched should be set immediately on making a selection.Inhale
That makes sense . Thanks !Sirkin
Thanks for your sandbox, also. It's helpful to illustrate the issue.Inhale
V
1

For those using react-hook-form with yup, trigger onBlur inside onChange

<Controller
 name='dateOfBirth'
 control={control}
 render={({ field: { name, value, onChange, onBlur } }) => (
  <DatePicker
      selected={value}
      preventOpenOnFocus={true}
      maxDate={new Date()}
      dateFormat="yyyy-MM-dd"
      placeholderText='YYYY-MM-DD'
      onBlur={onBlur}
      onChange={(date: Date) => {
        onChange(date);
        onBlur();
      }}
      customInput={<DatePickerInput/>}
    />
Vaquero answered 15/11, 2022 at 16:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.