Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cyclic dependency issue #193

Closed
GazzaHazza opened this issue Mar 29, 2018 · 12 comments
Closed

Cyclic dependency issue #193

GazzaHazza opened this issue Mar 29, 2018 · 12 comments

Comments

@GazzaHazza
Copy link

Hi, I am having a issue with cyclic dependency within a schema. I have looked at this issue, but what was suggested didn't work for me.

yup.object().shape(
  {
    sub_building: yup.string(),
    building_name: yup.string().when('building_number', {
      is: building_number => !building_number,
      then: yup.string().required(),
    }),
    building_number: yup.string().when('building_name', {
      is: building_name => !building_name,
      then: yup.string().required(),
    }),
    street: yup.string().required(),
    town: yup.string().required(),
    county: yup.string().required(),
  },
  ['sub_building', 'building_name', 'building_number', 'street', 'town', 'county']
);

This is my schema. Basically i would like either building_number or building_name to be filled.

Thanks for your help in advance.

@davidchase
Copy link

Both ideas from #79 (comment) worked for me

const inst = yup.object({
  location: yup
    .object({
      state: yup.string(),
      county: yup.string()
    })
    .test(
      'is-optional',
      '${path}.state or ${path}.county is required',
      function({ state, county }) {
        return state === '' && county === '' ? false : true
      }
    )
})
// throws ValidationError: location.state or location.county is required
inst.validate({
    location: {
     state: '',
     county: ''
    }
})
// doesn't throw
inst.validate({
    location: {
     state: 'CA',
     county: ''
    }
})

or

const inst2 = yup.object().shape(
  {
    location: yup.object().shape({
      state: yup
        .string()
        .when('county', {
           is: '',
           then: yup.string().required(),
           otherwise: yup.string()
        }),
      county: yup
        .string()
        .when('state', {
           is: '',
           then: yup.string().required(),
           otherwise: yup.string()
        })
    }, ['county', 'state'])
  }
)

I needed either county or state to be filled in

@MarcosApostolo
Copy link

Hi, the second solution worked for me. Thank you very much.

@web2wire
Copy link

web2wire commented Jun 4, 2018

I am having this same issue but both of the solutions seems to suggest that the optional fields needs to be present in their own sub-object, location in the above case.

In my case there is one single level object of user data where the fields in question are mixed in with the rest of the users data. Specifically, to register, a user has to specify an entry in one of the two telephone fields. It's actually a little more complicated than that as certain types of users may have to fill in one of three or more fields but the 'two field' case should be general enough.

The proposed solutions appear to only work if I manually munge the data received so that { name: "John Doe", company: "Test Inc", mobile: "012345678", phone: "" } becomes { name: "John Doe", company: "Test Inc", telephone: { mobile: "012345678", phone: "" } } for the purposes of form validation, and then restructured again for submission. Which seems rather clunky and potentially error prone.

There must be a general solution to the 'one of set of fields is required' problem that doesn't require data to be artificially bent?

@davidchase
Copy link

I think it would be helpfully to post your data you are attempting to validate as well as your current validation schema. What I posted is simply the scenario that I had to deal with so I outlined my solution based on previous issues. I don’t think my solution would work for everyone thus if you would like help please post sample data and schema. :)

@cenda
Copy link

cenda commented Nov 12, 2018

Hi, could anyone tell me where is issue, or what is correct approach, when you have scenario with 'all or nothing' is valid? I've tried to mimic @davidchase solution with following code, but witout success :(

Thank you for every help

var schema = yup.object().shape({
  address: yup.object().shape({
    city: yup
      .string()
      .when('zip_code', {
           is: val => val.length > 0,
           then: yup.string().required(),
           otherwise: yup.string()
        })
      .when('street', {
           is: val => val.length > 0,
           then: yup.string().required(),
           otherwise: yup.string()
        }),
    zip_code: yup
      .string()
      .when('city', {
           is: val => val.length > 0,
           then: yup.string().required(),
           otherwise: yup.string()
        })
      .when('street', {
           is: val => val.length > 0,
           then: yup.string().required(),
           otherwise: yup.string()
        }),
    street: yup
      .string()
      .when('zip_code', {
           is: val => val.length > 0,
           then: yup.string().required(),
           otherwise: yup.string()
        })
      .when('city', {
           is: val => val.length > 0,
           then: yup.string().required(),
           otherwise: yup.string()
        }),
  }, ['street', 'zip_code', 'city'])
});

schema.isValid({
  address: {
    street: 'Street Name', 
    city: 'City Name',
    zip_code: '12345'
  }
}).then(valid => console.log(valid))

@jquense
Copy link
Owner

jquense commented Nov 12, 2018

@cenda the second argument to object.shape() is not an array of conflicting fields. its an array of field pairs. e.g. [['street', 'zip_code'], ['zip_code', 'city']] you need to make the list exhaustive

@cenda
Copy link

cenda commented Nov 12, 2018

umm, sorry, but I'm afraid I don't understand

@jquense
Copy link
Owner

jquense commented Nov 12, 2018

#176 (comment)

@jquense jquense closed this as completed Nov 12, 2018
@cenda
Copy link

cenda commented Nov 12, 2018

@jquense Thanks!

@msakal20
Copy link

@davidchase Thanks a lot!!! This works for me
#193 (comment)

@NitinGlasier
Copy link

NitinGlasier commented Apr 10, 2023

const CompanyProfileValidationSchema = Yup.object({
locations: Yup.array().of(
Yup.object().shape(
{
addressType: Yup.string().when(["address", "city", "country", "pincode", "state"], {
is: (address, city, country, pincode, state) => address || city || country || pincode || state,
then: Yup.string().required("Please Add FacilityType")
}),
country: Yup.string().when(["address", "addressType", "city", "pincode", "state"], {
is: (address, addressType, city, pincode, state) => address || addressType || city || pincode || state,
then: Yup.string().required("Please Add Country")
}),
city: Yup.string().when(["address", "addressType", "country", "pincode", "state"], {
is: (address, addressType, country, pincode, state) => address || addressType || country||pincode||state,
then: Yup.string().required("Please Add City")
}),
state: Yup.string().when(["address", "addressType", "city", "country", "pincode"], {
is: (address, addressType, city, country, pincode) => address || addressType || city || country || pincode,
then: Yup.string().required("Please Add State")
}),
address: Yup.string().when(["addressType", "city", "country", "pincode", "state"], {
is: (addressType, city, country, pincode, state) => addressType || city || country || pincode || state,
then: Yup.string().required("Please Add Address")
}),
pincode: Yup.string().when(["address", "addressType", "city", "country", "state"], {
is: (address, addressType, city, country, state) => address || addressType || city || country || state,
then: Yup.string().required("Please Add Pincode")
})
},
[
["addressType", "country"], ["addressType", "city"], ["addressType", "pincode"], ["addressType", "address"], ["addressType", "state"],
["country", "city"], ["country", "pincode"], ["country", "address"], ["country", "state"],
["address", "city"], ["address", "pincode"], ["address", "state"],
["state", "city"], ["state", "pincode"],
["city", "pincode"]
]
)
)
});

it's a right code for cyclic dependency if not than please help how to solve this

@Junaid300
Copy link

I faced same issue. But i had to pass same dependency twice and it worked for me. I am not sure what is the reason for this. Can someone example?

yup.object().shape(
  {

    building_number: yup.string().when('building_number', {
      is: building_name => Boolean(building_name),
      then: yup.string().required(),
    }),
    street: yup.string().required(),
    town: yup.string().required(),
    county: yup.string().required(),
  },
  [['building_number', 'building_number']]
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants