如何使用Yup验证开始日期是否在结束日期之后?

34

我有一个使用Formik库创建事件的表单。 我需要检查开始日期是否与结束日期重叠,反之亦然。 我有两个日期选择器来选择日期和时间。 如何使用Yup进行验证,并在它们重叠时显示错误消息?

提前感谢您的帮助。

const validationSchema = Yup.object().shape({
    eventName: Yup.string()
        .min(1, "Must have a character")
        .max(10, "Must be shorter than 255")
        .required("Must enter an event name"),

    email: Yup.string()
        .email("Must be a valid email address")
        .max(255, "Must be shorter than 255")
        .required("Must enter an email"),

    eventStartDate: Yup.date()
        .required("Must enter start date"),


    eventEndDate: Yup.date()
        .required("Must enter end date")


})

var defaultValue = new Date().toDateString


export default function EventForm(){

    return (
        <Formik 
        initialValues={{eventName: "", email: "", }}
        validationSchema={validationSchema}
        onSubmit={(values, {setSubmitting, resetForm}) => {
            setTimeout(() => {

        }}
        >
            { ({
                values, 
                errors, 
                touched, 
                handleChange, 
                handleBlur,
                handleSubmit,
                isSubmitting
            }) => (
                <form onSubmit={handleSubmit}>
                <div className="input-row">
                    <TextField
                        id="eventName"
                        label="Event Name"
                        margin="normal"
                        variant="filled"
                        onChange={handleChange}
                        onBlur={handleBlur}
                        value={values.eventName}
                        className={touched.eventName && errors.eventName ? "has-error" : null}
                        />
                    <Error touched={touched.eventName} message={errors.eventName}/>
                </div>

                <div className="dateHolder">
                    <div className="startDate">
                            <TextField 
                                id="eventStartDate"
                                label="Event Start Date"
                                type="datetime-local"
                                InputLabelProps={{
                                    shrink: true
                                }}
                                format="yyy-dd-mm HH:MM:ss"
                                onChange={handleChange}
                                onBlur={handleBlur}
                                value={values.eventStartDate}
                            />
                            <Error touched={touched.eventStartDate} message={errors.eventStartDate}/>
                    </div>

                    <div className="endDate">
                    <TextField 
                                id="eventEndDate"
                                label="Event End Date"
                                type="datetime-local"
                                InputLabelProps={{
                                    shrink: true
                                }}
                                format="yyy-dd-mm HH:MM:ss"
                                onChange={handleChange}
                                onBlur={handleBlur}
                                value={values.eventEndDate}
                            />
                            <Error touched={touched.eventEndDate} message={errors.eventEndDate}/>
                    </div>
                </div>


                <div className="input-row">
                <button type="submit" disabled={isSubmitting} >
                    Submit
                </button>
          </div>

            </form>
            )}
        </Formik>
    )

}
7个回答

63

使用 ref,它可以正常工作。

yup.object().shape({
              startDate: date(),
              endDate: date().min(
                  yup.ref('startDate'),
                  "end date can't be before start date"
                )
            }); 

1
我完全同意你的看法 @gogaz。 - Ali Kaan Bacı

28

您可以使用when条件:

eventStartDate: yup.date().default(() => new Date()),
eventEndDate: yup
        .date()
        .when(
            "eventStartDate",
            (eventStartDate, schema) => eventStartDate && schema.min(eventStartDate))

2
在 when 语句中,应该是 "eventStartDate" 吧? - Vadym P
1
这对于相同的开始和结束日期以及相同的时间是否有效?对我来说没有起作用。 - CraZyDroiD
这篇文章提供了一个类似的示例,但更详细地补充了验证方式。 - PaKo Anguiano

8

Nader的答案对我有用。 但是我有一些额外的验证条件,如果一个复选框被选中,则验证开始日期是否在结束日期之前。所以,我想出了这段代码。留下来以防将来有人需要。

Yup.object.shape({
    ServiceCheck: Yup.boolean().default(false),
    StartDateTime: Yup.date().when('ServiceCheck', {
      is: (ServiceCheck=> {
        return (!!ServiceCheck) ? true : false;
      }),
      then: Yup.date().required('Start Date/Time is required')
    }).nullable(),
    EndDateTime: Yup.date().when('ServiceCheck', {
      is: (ServiceCheck=> {
        return (!!ServiceCheck) ? true : false;
      }),
      then: Yup.date().min(Yup.ref('StartDateTime'),
        "End date can't be before Start date").required('End Date/Time is required')
    }).nullable(),
})

无条件

Yup.object().shape({
              StartDate: Yup.date(),
              EndDate: Yup.date().min(
                  Yup.ref('StartDate'),
                  "End date can't be before Start date"
                )
            }); 

1
这段代码没有检查开始日期和结束日期是否相同,你能帮我解决一下吗? - CraZyDroiD

0
对于日期来说可能还可以,但对于一天中的时间来说就不行了。
比如:from = 12:00,to = 15:00 - 它无法通过 yup 的验证。 总是出错。

0
eventStartDate: Yup.date().default(() => new Date()),
    startDate: Yup.date()
      .when(
        'eventStartDate',
        (eventStartDate, Yup) => eventStartDate && Yup.min(eventStartDate, 'Date can select from Current Date')
      )
      .required('Start-date is Required'),

0
这是我用来验证时间/日期的方法,假设我有两个输入字段:开始时间和结束时间。这是一个冗长的解决方案,但它可以处理所有的情况。我在这个示例中使用了date-fns库,但也可以替换为其他库。
import { isAfter, isBefore, isEqual, isValid } from 'date-fns';

const validateTime: Schema = yup
  .object({
    startTime: yup.mixed().test({
      name: 'validator-time',
      test: function (startTime: Date | null) {
        if (startTime) {
          if (isValid(startTime)) {
            const { from } = this;
            const formValue = from[0].value;
            const endTime: Date | null = formValue.endTime;
            if (isValid(endTime) && endTime) {
              if (isEqual(endTime, startTime) || isAfter(startTime, endTime) || isBefore(endTime, startTime)) {
                return this.createError({
                  message: "start time should be before end time" ,
                  path: 'startTime',
                });
              }
              return true;
            }
            return true;
          }
          return this.createError({
            message: 'Invalid Time',
            path: 'startTime',
          });
        }
        return this.createError({
          message:"Required field",
          path: 'startTime',
        });
      },
    }),
    endTime: yup.mixed().test({
      name: 'validator-time',
      test: function (endTime: Date | null) {
        if (endTime) {
          if (isValid(endTime)) {
            const { from } = this;
            const formValue = from[0].value;
            const startTime: Date | null = formValue.startTime;
            if (isValid(startTime) && startTime) {
              if (isEqual(endTime, startTime) || isAfter(startTime, endTime) || isBefore(endTime, startTime)) {
                return this.createError({
                  message: 'end time cannot be before start time',
                  path: 'endTime',
                });
              }
              return true;
            }
            return true;
          }
          return this.createError({
            message: 'invalid time',
            path: 'endTime',
          });
        }
        return this.createError({
          message:'required field',
          path: 'endTime',
        });
      },
    }),
  })
  .required();

0
@seem7teen,谢谢你的代码,它帮助我构建了我所需要的东西。只是要注意,正如@Roman指出的那样,它在html type="time"上不起作用。不过,我稍微修改了一下,并且缩短了它,以适应我使用html时间输入字段的需求。
const timeValidationSchema = Yup.object({
    startTime: Yup.mixed().test({
        name: 'validator-time',
        test: function (startTime) {
            const { from } = this
            const formValue = from[0].value
            const endTime = formValue.endTime
            if (endTime && startTime >= endTime) {
                return this.createError({
                    message: 'Start time cannot occur before end time.',
                    path: 'startTime',
                })
            } else {
                return true;
            }
        }
    }).required('A start time is required.'),
    endTime: Yup.mixed().test({
        name: 'validator-time',
        test: function (endTime) {
            if (endTime) {
                return true
            }
        }
    }).required('An end time is required.'),
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接