Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yup validate either one of two fields is required (one of them is an array of numbers)

I'm using Formik with Yup and Typescript, and I have this as an initial value of the form ...

const initialValues = {
    title: "",
    overview: "",
    related_items_id: [],
    short_desc: ""
};

And here's my schema ...

const formSchema = Yup.object().shape({
    title: Yup.string()
        .trim()
        .required("This field is required."),
    overview: Yup.string().required("This field is required."),
    related_items_id: Yup.array()
        .min(1, "Pick at least 1 item")
        .of(Yup.number().required("This field is required.")),
    short_desc: Yup.string().required("This field is required.")
});

Now, I need either the related_items_id array or the short_desc to be required, if one is filled with data the other is not required and vise Versa, how can I accomplish that using something like when in yup?

Here's a codesandbox I created to show the error that I'm getting when trying to use the when method of Yup ...

https://codesandbox.io/s/formik-yup-required-one-or-the-other-nextjs-gujqv

like image 862
Ruby Avatar asked Jan 26 '23 09:01

Ruby


2 Answers

You can achieve this by creating a type that is interdepedent on related_items_id and short_desc

export interface BaseType {
    title: string;
    overview: string;
}

interface RelatedItemsType extends BaseType {
  related_items_id?: Array<any>;
  short_desc?: never;
}

interface ShortDescType extends BaseType {
  related_items_id?: never;
  short_desc?: string;
}

export type InitialValueType = RelatedItemsType | ShortDescType;

and you can make use of it like this

const initialValues: InitialValueType = {
    title: "",
    overview: "",
    related_items_id: [],
    // short_desc: "" no longer required
};

For conditionally setting your formSchema, checkout the docs Conditionally Set Required Field (Yup).

const basicFormSchema = Yup.object().shape(
    {
      title: Yup.string()
        .trim()
        .required("This field is required."),
      overview: Yup.string().required("This field is required."),
      related_items_id: Yup.array().when("short_desc", {
        is: "",
        then: Yup.array()
          .min(1, "Pick at least 1 item")
          .of(Yup.number().required("This field is required.")),
        otherwise: Yup.array()
      }),
      short_desc: Yup.string().when("related_items_id", {
        is: relatedItemsId => relatedItemsId.length === 0,
        then: Yup.string().required("This field is required."),
        otherwise: Yup.string()
      })
    },
    [["related_items_id", "short_desc"]]
  );
like image 141
ioedeveloper Avatar answered Feb 05 '23 14:02

ioedeveloper


This is how you check if at least one of them is completed.

const schema = yup.object().shape({
  'fieldOneName': Yup.string()
  .when('fieldTwoName', {
    is: (fieldTwo) => !fieldTwo || fieldTwo.length === 0,
    then: Yup.string()
      .required('At least one of the fields is required'),
  }),
  'fieldTwoName': Yup.string()
  .when(codiceFiscale.name, {
    is: (fieldOne) => !fieldOne || fieldOne.length === 0,
    then: Yup.string().
      .required('At least one of the fields is required'),,
  })
}, ['fieldOneName', 'fieldTwoName']) // <-- HERE!!!!!!!!
like image 28
Artan M. Avatar answered Feb 05 '23 16:02

Artan M.