jaredpalmer / formik

Build forms in React, without the tears 😭
https://formik.org
Apache License 2.0
33.86k stars 2.78k forks source link

Per schema conditional validation #1659

Open jfsalaza opened 5 years ago

jfsalaza commented 5 years ago

I'm trying to build a form with Formik but I'm unable to do the type of conditional validation that I need for my schemas. I have a Formik form where I'm trying to fill out an object called profile. The object looks something like this, this is what I have in my Formik initialValues:

const profile = {
    profile_first_name: undefined,
    profile_last_name: undefined,
    profile_time_zone: undefined,
    profile_company_name: undefined,
    profile_work_histories: [
        profile_work_histories
    ],
    profile_educations: [
        profile_educations
    ]
};

Here is how my schema looks like:

export const ClientCreateAccountSchema = Yup.object().shape({
    profile: Yup.object().shape({
        profile_first_name: Yup.string().required('Cannot be empty'),
        profile_last_name: Yup.string().required('Cannot be empty'),
        profile_time_zone: Yup.string().required('Cannot be empty').length(3, 'Must be 3 characters (ex.PST)'),
        profile_company_name: Yup.string().required('Cannot be empty'),
        profile_work_histories: profileWorkHistory,
        profile_educations: profileEducationSchema
    })
});

export const profileEducationSchema = Yup.array().of(Yup.object().shape({
    profile_education_school_name: Yup.string().required(),
    profile_education_degree_type: Yup.string().required(),
    profile_education_degree_major: Yup.string().required(),
    profile_education_school_country: Yup.string().required(),
    profile_education_school_province: Yup.string().required(),
    profile_education_start_date: Yup.string().required(),
    profile_education_end_date: Yup.string().matches(/^((0[1-9])|(1[0-2]))-[0-9]{4}$/, 'Must be in MM-YYYY format')
}));

export const profileWorkHistory = Yup.array().of(Yup.object().shape({
    profile_work_history_company_name: Yup.string().required(),
    profile_work_history_employment_url: Yup.string().url(),
    profile_work_history_number_of_attorneys: Yup.number('Must be a number').required(),
    profile_work_history_company_country: Yup.string().required(),
    profile_work_history_company_province: Yup.string().required(),
    profile_work_history_company_city: Yup.string().required(),
    profile_work_history_position: Yup.string().required(),
    profile_work_history_employment_start_date: Yup.string().required(),
    profile_work_history_employment_end_date: Yup.string().required(),
    profile_work_history_is_current: Yup.bool().required()
}));

Keep in mind that I also have 4 other subschemas at that level, but I removed them for simplicity. The other subschemas are called profileBarAssociationsSchema, profileJurisdictionSchema, profileLanguagesSchema, profileIndustrySchema. They all have up to 6 fields that need to be filed out.

So far this is what I've tried:

But I get an error everything I tried to add a new field to the FieldArray and start filling out the second item instead of the first one.

Another thing I've tried was to use Yup.when but I have so many fields that it is hard to keep track of all the conditional validation combinations, that makes it almost impossible .

My question is how can I configure my ClientCreateAccountSchema so that the sub schemas are validated separately from each other? In other words, how can I my schema only validate the respective subchema when touched and not activate the other subschema? Is this something I can do with Yup? or is this something with Formik?

What other suggestions do you guys have?

jaredpalmer commented 5 years ago

A few options:

Enzyoh commented 5 years ago

Yup has conditional validation using 'when' and passing through the context . here. I'm also unsure how to take advantage of this within formik. see my question earlier here

Enzyoh commented 5 years ago

@jaredpalmer On another note I think validationSchema = { values => { does not pass through the values . validate = { values => { will do though.

jfsalaza commented 5 years ago

Is it possible to separate the Form into smaller forms and submit them all at once ?