11
votes

I'm using formik for form management in reactjs, i have a question on validation with yup.

I have two fields, ones is a select control to select the country, and the other one is a zipcode.

In the country array we have the regex to validate the zipcode, and the idea is to validate the entered zipcode using the regex of the currently selected country, someone can give a clue on how to do this.

5
Hope this answer to another similar question can help: stackoverflow.com/questions/49394391/…Eric Tan

5 Answers

21
votes

An example of a field that requires a numeric value that cannot be higher than the multiplication of two other field's values

const validationSchema = Yup.object().shape({
    num1: Yup.number().positive().required('This field is required.'),
    num2: Yup.number().positive().required('This field is required.'),
    num3: Yup.number().positive().required('This field is required.').when(['num1', 'num2'], (num1, num2, schema) => {
        return num1 > 0 && num2 > 0 ? schema.max(num1 / num2) : schema.max(0);
    })
});
2
votes

Use .when() and pass it a function which returns the schema for the ZIP code based on the value of the country.

2
votes
let schema = object({
  isBig: boolean(),
  count: number()
    .when('isBig', {
      is: true, // alternatively: (val) => val == true
      then: yup.number().min(5),
      otherwise: yup.number().min(0),
    })
});
2
votes

Here's an example of enforcing a datepicker's end date being after the start date:

const schema = Yup.object().shape({
    start_date: Yup.date()
        .typeError('Start Date is required')
        .required('Start Date is required'),
    end_date: Yup.date()
        .typeError('End Date is required')
        .required('End Date is required')
        .when('start_date', (start_date) => {
            if (start_date) {
                return Yup.date()
                    .min(start_date, 'End Date must be after Start Date')
                    .typeError('End Date is required')
            }
        }),
})

It was required to put the if statement to validate correctly while the form was loading, and it was also required to put the typeError rule in to validate correctly when the start date was selected but the end date wasn't yet.

The important thing is you can see usage of when; the first param is the field to check against, and the second param is the validation function which returns a Yup validation object.

I tried to just return true or false, but it seemed to throw errors, so it's a bit more complex than it just being a pure validation function.

1
votes

I had the exact same problem. I was a able to use when to solve it.

import { object, string } from 'yup';

const validCountries = ['US', 'CA'];

const zipRegexes = {
    US: /^\d{5}(?:-?\d{4})?$/,
    CA: /^[ABCEGHJKLMNPRSTVXY]\d[A-Z]\d[A-Z]\d$/
};

const addressSchema = object().shape({
    country: string()
        .oneOf(validCountries, 'Please select a country from the list above')
        .required('Please select a country from the list above'),
    /* Other fields
    .
    .
    .
    */
    zip: string()
        .trim()
        .required('Required')
        .transform(value => value.toUpperCase())
        .when('country', (country, schema) => {
            if (
                string()
                    .oneOf(validCountries)
                    .required()
                    .isValid(country)
            ) {
                return schema.matches(
                    zipRegexes[country],
                    `not a valid ${country} zip code`
                );
            }

            return schema;
        })
});