Stam
Stam

Reputation: 2490

How to access a parent value inside an array in yup validation

I have defined a yup schema

export const ValidationSchema = yup.object().shape({
    dateTo: yup
        .date()
        .required(MandatoryFieldMessage)

   uebernachtungen: yup.array().of(
     yup.object().shape({
     ort: yup
            .string()
            .trim()
            .max(100, Maximum100CharactersMessage)
            .required(MandatoryFieldMessage),

    bis: yup
            .date()
            .required(MandatoryFieldMessage)
            .max(yup.ref("dateTo"), "display message") }))
})

I just want to use the value of dateTo inside the array, so that all the bis in the uebernachtungen will not be allow do have a value greater than dateTo.

The problem is that I can access items inside the array like ort but I cannot access items out of it like dateTo.

So in this case yup.ref("dateTo") will return undefined but yup.ref("ort") will be correct. It seems that array has its own context and I cannot access to the parent context.

How would be this possible?

Upvotes: 6

Views: 15721

Answers (5)

For some reason, the initial answer didn't work for me, but I did manage to find another solution using Yup.lazy. Basically, just wrap everything around Yup.lazy

export const ValidationSchema = yup.lazy((globalContext) => yup.object().shape({
    dateTo: yup
        .date()
        .required(MandatoryFieldMessage)

   uebernachtungen: yup.array().of(
     yup.object().shape({
     ort: yup
            .string()
            .trim()
            .max(100, Maximum100CharactersMessage)
            .required(MandatoryFieldMessage),

    bis: yup
            .date()
            .required(MandatoryFieldMessage)
            .max(globalContext.dateTo, "display message") }))
}))

Upvotes: 0

Abhin Pai
Abhin Pai

Reputation: 492

Try this way, It worked fine for me.

import { array, date, object, string } from 'yup';

export const ValidationSchema = object().shape({
  dateTo: date().required('MandatoryFieldMessage'),
  uebernachtungen: array().when('dateTo', (dateTo, schema) =>
    schema.of(
      object().shape({
        ort: string().trim().max(100, 'Maximum100CharactersMessage').required('MandatoryFieldMessage'),
        bis: date().required('MandatoryFieldMessage').max(dateTo, 'display message')
      })
    )
  )
});

Upvotes: 0

Pushpendra Kumar
Pushpendra Kumar

Reputation: 1674

Simply create a global variable dateToTmp and assign value by test method: check the line number 7

let dateToTmp;
const ValidationSchema = yup.object().shape({
    dateTo: yup
        .date()
        .required(MandatoryFieldMessage)
        .test('dateToTmp', 'assign value to variable', (value) => {
            dateToTmp = value;
            return true;
        })
    uebernachtungen: yup.array().of(
    yup.object().shape({
        ort: yup
            .string()
            .trim()
            .max(100, Maximum100CharactersMessage)
            .required(MandatoryFieldMessage),
        bis: yup
            .date()
            .required(MandatoryFieldMessage)
            .test('dateToCheck', 'display message', function (value) {
            // access dateTo from passed context
            return !(value > dateToTmp)
    })) 
})

Upvotes: -1

Dipesh KC
Dipesh KC

Reputation: 2463

I came through similar issue. I used this workthrough with success.

Idea: Pass whole form-data as a context to the schema and access any form value using

this.options.context

 const ValidationSchema = yup.object().shape({
     dateTo: yup
         .date()
         .required(MandatoryFieldMessage)

     uebernachtungen: yup.array().of(
         yup.object().shape({
             ort: yup
                 .string()
                 .trim()
                 .max(100, Maximum100CharactersMessage)
                 .required(MandatoryFieldMessage),

             bis: yup
                 .date()
                 .required(MandatoryFieldMessage)
                 .test('dateToCheck', 'display message', function (value) {
                    // access dateTo from passed context
                   if(value>this.options.context.dateTo) return false
                   return true }),

         })) })

Passing Context

Without Formik

Send your Form data as a context while validating

 ValidationSchema.validateSync(data, {context: form_data})

With Formik

Use validate instead of validationSchema

Pass your Form data as 4th argument in validateYupSchema which represents context and can be accessed later in schema.

Pass your schema as 2nd argument in validateYupSchema.

    <Formik
      validate={(value) => {
        try {
          validateYupSchema(value, ValidationSchema, true, value);
        } catch (err) {
          return yupToFormErrors(err); //for rendering validation errors
        }

        return {};
      }}

       onSubmit={} />

Upvotes: 5

Jean Crus
Jean Crus

Reputation: 9

Something like this could work, if i understood correctly ur question...

Example of using test to get value from yup scheme

Upvotes: 0

Related Questions