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

Can't get zod superRefine / refine to work on zod.object() . #4208

Closed
1 of 5 tasks
metalsadman opened this issue Apr 5, 2023 · 5 comments
Closed
1 of 5 tasks

Can't get zod superRefine / refine to work on zod.object() . #4208

metalsadman opened this issue Apr 5, 2023 · 5 comments

Comments

@metalsadman
Copy link

metalsadman commented Apr 5, 2023

What happened?

The issue is superRefine don't get called at all if I don't make the whole schema partial() which creates another problem as errors won't appear (not unless I edit the fields/manually trigger it) since partial makes all of the properties optional so resulted in me doing a workaround where the required if condition is done outside of zod schema ie. on a vue watch.

// validation composable
type SomeType = {
  type: number;
  firstVal: boolean;
  secondVal: boolean;
}
const schema = z.object({
      type: z.number(),
      firstVal: z.boolean(),
      secondVal: z.boolean(),
    })
    .partial() // if this is removed then superRefine won't ever get called
    .superRefine((data, customError) => {
      console.log('At Refinements -> ', data); // never gets called not unless I make the object partial
      if (data.type === 1) {
        if (data.firstVal === false && data.secondVal === false) {
          customError.addIssue({
            code: z.ZodIssueCode.custom,
            path: ['firstVal'],
            message: 'One must be checked',
          });
          customError.addIssue({
            code: z.ZodIssueCode.custom,
            path: ['secondVal'],
            message: 'One must be checked',
          });
        }
      }
    });
const validationSchema = toFormValidator(schema);
const { ...vee } = useForm<SomeType>({
    validationSchema,
    // even if I initialize the value superRefine won't get called
});
// ... useField codes

// script setup
// ... above composable used
onMounted(async ()=> {
  const validationResult = await vee.validate({ mode: 'silent' })
  console.log({ validationResult }) // errors prop is empty an object {} & valid is true
}

I don't know if it's related to this colinhacks/zod#479, which I also tried suggestions like zod's merge and extend methods but to no avail.

Reproduction steps

...

Version

Vue.js 3.x and vee-validate 4.x

What browsers are you seeing the problem on?

  • Firefox
  • Chrome
  • Safari
  • Microsoft Edge

Relevant log output

No response

Demo link

n/a

Code of Conduct

@abh1nash
Copy link

A workaround that I am using is to add the fields to be compared with superRefine to a separate z.object.

// Here I am making sure either phone number or mobile number is always present
// Both can't be empty
// I am creating a separate contact object which I can set to partial without affecting the parent object properties
const profileSchema = z.object({
  firstName: z.string().nonempty(),
  lastName: z.string().nonempty(),
  email: z.string().nonempty().email(),
  contact: z.object({
      mobile: z.string(),
      phone: z.string(),
    })
    .partial()
    .superRefine((v, ctx) => {
      if (v.mobile || v.phone) return true;
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: "You must add at least one contact number.",
        path: ["mobile"],
      });
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: "You must add at least one contact number.",
        path: ["phone"],
      });
    }),
  address: z.string().nonempty(),
});

This definitely won't work for all cases, especially when you do not have control over the data format to be sent to the server. You could change the format of the object after validation with handleSubmit though. However, it would be great if this issue was addressed by VeeValidate.

@logaretm
Copy link
Owner

logaretm commented Apr 14, 2023

Not sure if this is a vee-validate issue, marking a schema as partial or not and its effect or running the superRefine is probably not within vee-validate responsibility.

For example I can run the schema with schema.parse and it won't run the superRefine either unless all values are present. Unless there is something or a flag we can pass to parse that I'm unaware of. Any suggestions?

Upon reading the issue in zod's repo, it does seem like a behavior they have baked in. Nothing vee-validate can do about this, if I'm wrong please let me know and we can resolve it.

@metalsadman
Copy link
Author

@logaretm ok :(, I'll try @abh1nash suggestion above.

@thinhbg2812
Copy link

@logaretm ok :(, I'll try @abh1nash suggestion above.

Did you manage to deal with this problem yet ?

@allanpilima
Copy link

This is not a vee-validate issue. I'm having the same with react. Honestly, not having an option to validate one field against another is super weird. Currently I cannot change this lib for yup, cause my company does not allows, so I have to create a function that receives a getter for me to validate one value against another. It generates a super messy code that wasn't the case with yup

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

5 participants