Yup: [QUESTION] Validating on a field based on multiple separate conditions

Created on 6 Oct 2019  路  2Comments  路  Source: jquense/yup

I have the following Formik form with a Dropdown and two Date pickers. The date pickers have conditional validation: for both of them, if the user selects the First item from the dropdown, we make the fields required.

However, for the second DatePicker (EndDate) - I want an additional validation that restrict the date to be no more than 6 months from the StartDate and never less than StartDate. And this should only be applied if the user has First as the selected item.

<Formik
    initialValues={{ Dropdown1: "", StartDate: "", EndDate: "" }}
    onSubmit={(values, actions) => {
        setTimeout(() => {
            alert(JSON.stringify(values, null, 2));
            actions.setSubmitting(false);
        }, 1000);
    }}
    validationSchema={Yup.object().shape({
        StartDate: Yup.date.when("Dropdown1", (data, schema) => {
            data.Dropdown1 === "First" ? schema.required("this is a required field") : schema
        })

        EndDate: Yup.date.when("Dropdown1", (data, schema) => {
            data.Dropdown1 === "First" ? schema.required("this is a required field") : schema

            // Here I need another validation that checks EndDate can't be more than 6 months from StartDate and never less than StartDate
        })
    })}
    render={props => (
    <form onSubmit={props.handleSubmit}>
        <CustomDropdown
            dropdownItems=[
                { caption: "Select something", Id: "" },
                { caption: "First", Id: "1" },
                { caption: "Second", Id: "2" }
            ]
            onBlur={props.handleBlur}
            value={props.values.name}
            name="Dropdown1"
        />
        <CustomDatePicker
            name="StartDate"
        />
        <CustomDatePicker
            name="EndDate"
        />
        {props.errors.name && <div id="feedback">{props.errors.name}</div>}
        <button type="submit">Submit</button>
    </form>
    )}
/>

Most helpful comment

In there general there are two approaches to doing complex conditional validation:

  1. use when(), it supports specifying multiple dependencies like when(['startDate' 'endDate], () => `. This approach is good for directed conditions, e.g. dependencies with no cycles, because it ensures fields are processed in the correct order (topographically). If you have cycles tho it doesn't work super well (e.g. startDate depends on EndDate which depends on startDate)

  2. Move validation to a parent. You can declare a custom test on the parent object that compares all the child values and throws the right error, this is the most straight forward approach but is a bit harder to make work with Form libraries that expect all errors to be keyed by a fields specific path. You have to get a bit creative with error displaying, which i don't think is a bad thing, heavily interdependent fields don't always map neatly to a single field's error, and may require more intentional UI anyway.

All 2 comments

In there general there are two approaches to doing complex conditional validation:

  1. use when(), it supports specifying multiple dependencies like when(['startDate' 'endDate], () => `. This approach is good for directed conditions, e.g. dependencies with no cycles, because it ensures fields are processed in the correct order (topographically). If you have cycles tho it doesn't work super well (e.g. startDate depends on EndDate which depends on startDate)

  2. Move validation to a parent. You can declare a custom test on the parent object that compares all the child values and throws the right error, this is the most straight forward approach but is a bit harder to make work with Form libraries that expect all errors to be keyed by a fields specific path. You have to get a bit creative with error displaying, which i don't think is a bad thing, heavily interdependent fields don't always map neatly to a single field's error, and may require more intentional UI anyway.

@jquense how I which you can give a code sample of the second solution or point me to where I can find such resource

Was this page helpful?
0 / 5 - 0 ratings