Yup: Validate child against parent.

Created on 23 May 2018  路  14Comments  路  Source: jquense/yup

Hi,

I'm having a hard time figuring this out, not sure if it's even supported but I feel like it should be.

Basically I'm trying to mark a field as required if a referenced field is truthy. Something along the lines of

{
  requiredField: boolean(),
  nested: object().shape({
    conditional: when('$parent.requiredField', ....)
  })
}

Something similar was being discussed over at https://github.com/jaredpalmer/formik/issues/539 but that convo didn't get very far.

Is there no way to reference a key in a parent schema?

Most helpful comment

We had a similar issue, but solved it this way:

{
  requiredField: boolean(),
  nested: object().when('requiredField', {
    is: true,
    then: object({
      foo: string.required(),
      // ...etc
    })
}

All 14 comments

You could go the other way - create the reference to your child using .ref on the same level where your parent is and do the validation there.

@latviancoder - I'm also running into this issue, and it's not immediately clear (to me at least) how to accomplish this using .ref - any chance you could provide an example?

I ended up passing in the entire object that I'm trying to validate as context so I could grab the values I care about.

const mySchema = {
  requiredField: boolean(),
  nested: object().shape({
    conditional: string().when("$requiredField", (requiredField, schema) =>
      requiredField ? schema.required() : schema
    )
  })
}

const myObj = {
  requiredField: true,
  nested: {
    conditional: "Some string"
  }
}

const isValid = mySchema.isValidSync(myObj, {context: myObj})

We had a similar issue, but solved it this way:

{
  requiredField: boolean(),
  nested: object().when('requiredField', {
    is: true,
    then: object({
      foo: string.required(),
      // ...etc
    })
}

Hi @jaclynj using this I'll have to create 2 complete objects but I'm have validate just one field based on the parent value. There's some way? Thank you

test functions have access to this.parent which is the immediate parent object if it exists. For checking values higher than that there is no support, There was some work in #201 but progress seems to have stalled

@jquense would you point me to documentation showing that test has access to this.parent, when I try to access it all I get is the

formik.js:6202 Uncaught (in promise) TypeError: Cannot read property 'length' of undefined
    at yupToFormErrors (formik.js:6202)
    at eval (formik.js:5937)

sorry here's a an example of the error https://codesandbox.io/s/formik-checkbox-example-zcztz

if you open the console and then click on one of the checkboxes you'll see the error appear

OK nevermind, I forgot that test may not use an arrow function if it wishes to access this.parent

Hi,
I am having hard time to validate a field which is dependent on the value of an object in an array
This is my validation schema for an array of objects.
{name: Yup.array().when(['color'], {
is: (color) => {
if (color === 'red') {
return true;
}
return false;
},
then: Yup.array().of(
Yup.object().shape({
firstName: Yup.string().required('Required'),
lastName: Yup.string().required('Required'),
})
),
}),
phone: Yup.string(),
}
Now I want my phone field to display required error only if first name is not null. I am not able to access the value of first name in an array of object to validate phone.

Please help!

For anyone passing through, I was having the same issue with needing a field in an array of objects to only be required if a field at the top level had a particular value. As of 0.29.1 you can do this:

// Workaround as Yup doesn't support "when" conditions that access ancestor values
.test('emailLength', commonMessages.varcharTooLong, function(val) {
    return (this.from[1].value.entryType == kEntryType.scheduled) ?
        Yup.string().max(255).isValidSync(val) : true;
})
.test('emailValid', 'This doesn\'t look like a valid email address', function(val) {
    return (this.from[1].value.entryType == kEntryType.scheduled) ?
        Yup.string().email().isValidSync(val) : true;
})
.test('emailRequired', 'Please enter an email address', function(val) {
    return (this.from[1].value.entryType == kEntryType.scheduled) ?
        Yup.string().required().isValidSync(val) : true;
}),

Not ideal, but it's functional without resorting to building a schema dynamically before each validation.

Hi, I have similar situation with multiple array of object. @stecman Can you details how did you implement your solution ?
Currently i don't understrand from where you have the this.form[1] and the kEntryType

@JbPons it doesn't appear to be in the docs yet, but there's a more complete example in the origin PR. The this is context bound by Yup to the function you provide. That context includes form, which is an array of ancestors (this.form[0] is the parent, this.form[1] is the grandparent, etc). The kEntryType value is from my project and isn't relevant.

@JbPons it doesn't appear to be in the docs yet, but there's a more complete example in the origin PR. The this is context bound by Yup to the function you provide. That context includes form, which is an array of ancestors (this.form[0] is the parent, this.form[1] is the grandparent, etc). The kEntryType value is from my project and isn't relevant.

Ok, i see, since i use Typescript i don't have the form in the type. So i will do some nasty code to change the type until the @types/yup will be up to date. Thanks for the quick reply

Was this page helpful?
0 / 5 - 0 ratings

Related issues

RobBednark picture RobBednark  路  3Comments

juni0r picture juni0r  路  3Comments

jgcmarins picture jgcmarins  路  4Comments

Simmetopia picture Simmetopia  路  4Comments

cfteric picture cfteric  路  3Comments