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);
            }}           
          
        />

    )
gene b.
  • 10,512
  • 21
  • 115
  • 227

3 Answers3

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.

gene b.
  • 10,512
  • 21
  • 115
  • 227
1

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

Formik DatePicker Example

Shyam
  • 5,292
  • 1
  • 10
  • 20
  • 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. – gene b. May 23 '21 at 18:33
  • 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 . – Shyam May 23 '21 at 18:37
  • 2
    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. – gene b. May 23 '21 at 18:40
  • 1
    That makes sense . Thanks ! – Shyam May 23 '21 at 18:59
  • 1
    Thanks for your sandbox, also. It's helpful to illustrate the issue. – gene b. May 23 '21 at 21:21
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/>}
    />
zhuhang.jasper
  • 4,120
  • 4
  • 21
  • 29