Lester Arévalo
Lester Arévalo

Reputation: 462

conditional validation with yup

I have 3 fields in a form, the "type" field is select and from that list, some items enable or disable the "out" field, if is enable I need the "out" field to be less than the "in" field and vice-versa, but if the "out" field is disabled I don't need that validation, I was trying something with .when, but is not working, any ideas on how to do this?

  const [disableOutCounterField, setDisableOutCounterField] = useState(false);

  const schema = yup.object().shape({
    type: yup.string().required(requiredMessage),
    in: yup
      .number(numberMessage)
      .required(requiredMessage)
      .integer(integerMessage)
      .min(1, positiveMessage)
      .typeError(numberMessage)
      .when("out", {
        is: !disableOutCounterField,
        then: yup.number().moreThan(yup.ref("out"), moreThanMessage),
        message: moreThanMessage,
      }),
    out: yup
      .number(numberMessage)
      .integer(integerMessage)
      .typeError(numberMessage)
      .lessThan(yup.ref("in"), lessThanMessage),
  });

Upvotes: 1

Views: 5041

Answers (2)

phyatt
phyatt

Reputation: 19152

An alternative I found for this is to regenerate the object validationSchema from inside a useEffect.

This has the benefit of using useState without having them mapped to specific form fields ahead of time, such as if you set something conditionally from the database and don't want to set it as a hidden field somewhere.

const validationPiece = yup.object({
amount: yup
  .number()
  .typeError('Please enter an amount')
  .required('Please enter an amount')
});

const [validationSchema, setValidaitonSchema] = useState(yup.object({}));

const {
  register,
  handleSubmit,
  reset,
  formState: { errors },
} = useForm({
  resolver: yupResolver(validationSchema),
});

useEffect(() => {
  if (needNewPartOfForm) {
    const validationSchemaDict = {};
    if (needNewPartOfForm.xyz) {
      validationSchemaDict['xyz'] = validationPiece; // does this need a cloneDeep?
    }
    if (needNewPartOfForm.abc) {
      validationSchemaDict['abc'] = validationPiece;
    }
    setValidaitonSchema(yup.object(validationSchemaDict));
  }
}, [clientDocs, clientId, reset, teamId]);

Upvotes: 0

Peter B
Peter B

Reputation: 24280

The construct:

.when("out", {
  is: !disableOutCounterField,

compares the out value with !disableOutCounterField, and if they are equal, the then rule is applied. But quite likely they are never the same.

The check that is needed here is just the value of !disableOutCounterField by itself, for any value of out. This can be done using an expression:

.when("out", {
  is: value => !disableOutCounterField,

In words: for every out value, return !disableOutCounterField, and if it returns true, apply the then part.

Upvotes: 2

Related Questions