1
votes

Hi I'm again with Yup and formik doubt

I need validate Fromik field array using Yup My fields are like

[{startdate:'',endDate:'',name:''},{startdate:'',endDate:'',name:''}]

The Start/End Dates are Date object Before using Yup and formik i was doing validation to check selected date are already exits like this

 const checkDate=(selectedDate)=>{
    const isExisting = datas
      .filter((data) => data.startDate !== null || data.endDate !== null)
      .some(
        (data) =>
          new Date(data.startDate).toLocaleDateString() === selectedDate ||
          new Date(data.endDate).toLocaleDateString() === selectedDate,
      );

    if (isExisting) {
      toast.error('Date already exits');
      return false;
    }
}

I know this little weird. Some of you may have better option for this .I were doing all form validation manually like this ,After using formik and Yup helped lot.

Coming to point I need to validate date if user selected any ,Validate if selected date exits or not in array .Its formik field array My validation schema is like

export const CheckoutSchema = Yup.object().shape({
  Checkout: Yup.array()
    .of(
      Yup.object().shape({
        name: Yup.string().required(),
        startDate: Yup.date().required(),
        endDate: Yup.date().required(),
      }),
    )
});

I have checked some git pages and Stack overflow but I don't know will it work on my case here

1

1 Answers

0
votes

I had a similar issue and found the linked answer helpful, but there is no explanation of how it works. I was able to figure it out so hopefully this is more helpful.

Yup.addMethod(Yup.array, "unique", function(message) {
  return this.test("unique", message, function(list) {
    const mapper = x => x.name;
    const set = [...new Set(list.map(mapper))];
    const isUnique = list.length === set.length;
    if (isUnique) {
      return true;
    }

    const idx = list.findIndex((l, i) => mapper(l) !== set[i]);
    return this.createError({
      path: `[${idx}].name`,
      message: message,
    });
  });
});

const MySchema = Yup.object().shape({
  Checkout: Yup.array()
    .of(
      Yup.object().shape({
        name: Yup.string().required("Required"),
      })
    )
    .unique("Must be unique"),
});

Edit: This will actually create the error message at the specific field, which I find more user friendly. Also, this is only checking for uniqueness of the name field and assumes the name of the field in formik is ${index}.name.


Since I didn't test the above, here is my actual code, with nested objects in the array. This I have tested and confirmed does work.

Yup.addMethod(Yup.array, "unique", function(message, path) {
  return this.test("unique", message, function(list) {
    const mapper = x => x.description && x.description.number;
    const set = [...new Set(list.map(mapper))];
    const isUnique = list.length === set.length;
    if (isUnique) {
      return true;
    }

    const idx = list.findIndex((l, i) => mapper(l) !== set[i]);
    return this.createError({
      path: `tests[${idx}].description`,
      message: message,
    });
  });
});

const TestSchema = Yup.object().shape({
  tests: Yup.array()
    .of(
      Yup.object().shape({
        description: Yup.object().required("Required"),
      })
    )
    .unique("Test already added above"),
});