Open rlesniak opened 1 year ago
I doubt that the problem is linked to Zod's superRefine since the same issue arises with other resolvers like Yup, as I have tested. Although formState.isValid is true without a resolver, it is initially false when used with a resolver.
@bluebill1049 , could it be possible that there is something related to the usage of resolvers on the react-hook-form's end?
Its for sure not zods fault because its error object, either for common validation like nonempty()
or superRefine
is consistent
Have you tried debug with the following:
resolver: async (data, context, options) => {
// you can debug your validation schema here
console.log('formData', data)
console.log('validation result', await anyResolver(schema)(data, context, options))
return anyResolver(schema)(data, context, options)
},
Having the same issue when using the refine
method as well. Debugged as @bluebill1049 had shown and the output is exactly as expected by the resolver: an object with values
and errors
(with the error "thrown" by the refine
function populated in that object).
The isValid
prop is updated accordingly but the errors
object is still empty
I'm facing the same issue using superRefine
.
Having the same issue as @GuhPires.
Facing the same issues with superRefine
@bluebill1049 Any thoughts?
@bluebill1049 Any thoughts?
I will take a look at it 👍
Describe the bug using zod's superRefine validation function. errors object is empty. Its working fine in one order not the other way. ( check this video) Link: (Screen Recording 2023-08-21 at 2.49.16 PM.zip) Error Video Link: (https://github.com/react-hook-form/resolvers/assets/93373775/82cebe8b-228b-4a7b-a4fd-980cf97310bb)
To Reproduce Steps to reproduce the behavior:
Go to https://codesandbox.io/p/sandbox/elated-mendeleev-v92vvs See that errors object is empty, even though validation is correct.
Expected behavior errors object of the react form should have the errors of the respective fields.
Desktop (please complete the following information):
OS: macOS Ventura 13 Browser Chrome Version 116
Please let me know if the way of implementation is wrong !!
@bluebill1049 I noticed when trying to use the .refine
and .superRefine
it would work depending on placement. This was due to the fact that the ref
wouldn't necessarily be populated if there wasn't something registered for the path I was validating.
It would be nice if it could follow how setError
works, and allow paths to register errors
hey @stramel 👋 I think the whole scheme validation is based on registered input, not sure if it's a straightforward implementation switch and setError
was a single path update which is a lot easier.
Hey @bluebill1049 👋🏼
I'm currently using the Zod schema validation pretty easily but there are a couple of cases that aren't working well for me.
I have:
.refine
/.superRefine
for a non-registered input but for an array of objects, validating something on the object. These objects have a property that is registered.The setError
was more referring to how it can apply an error to a non-registered input.
validating the schema, the errors aren't being cleared after applying to a registered input (probably a separate issue)
A separate issue, hook form is field level based for validation and consistent validation strategy. I don't have a solution in my head without re-render the entre form on each form state.
validating the schema, the errors aren't being cleared after applying to a registered input (probably a separate issue)
A separate issue, hook form is field level based for validation and consistent validation strategy. I don't have a solution in my head without re-render the entre form on each form state.
That's fair, I will come up with a workaround for that.
I will note though, that the isValid
property still shows invalid even though there are no errors since Zod reports errors but they don't exist within the fields. I would expect that the errors object would have something if the isValid
property is reporting invalid.
Also facing this issue isValid
is false with empty errors
object. Does anyone know if manually setting the error path in refine
results in an error object? (I don't think this would be a solution in my case however, as the path is dynamic as part of an array input).
This only happens on first load but if you have a form and you submit or have it re-validate on change it will give you the error object.
Any update on this?
Any update on this?
Hi! Any update on this issue? I'm manually triggering the validation if isValid = false and all the inputs are filled. But it will be nice to have a native solution.
I had same issue and I have tried adding proper path to addIssue
and now it works. Before adding path, error was there without a path.
.superRefine((data, ctx) => {
if (data.table === "linear" && data.dimension < 0.5) {
ctx.addIssue({
code: z.ZodIssueCode.too_small,
minimum: 0.5,
type: "string",
inclusive: true,
message: "Value cannot be smaller than 0.5.",
path: ["dimension"],
});
}}
Hi! Any update on this issue? I'm manually triggering the validation if isValid = false and all the inputs are filled. But it will be nice to have a native solution.
@FoiDot Would you mind sharing the code for your solution? I tried the following, but errors
is still empty:
useEffect(() => {
if (!isValid) trigger('batches')
}, [isValid])
Hi! Any update on this issue? I'm manually triggering the validation if isValid = false and all the inputs are filled. But it will be nice to have a native solution.
@FoiDot Would you mind sharing the code for your solution? I tried the following, but
errors
is still empty:useEffect(() => { if (!isValid) trigger('batches') }, [isValid])
@stefan-girlich I did something like this:
useEffect(() => {
// I have some inputs working with Controller and setState.
// That means mode = 'all' | 'onChange' | etc doesn't work
// So I need to clean the errors manually with the clearErrors from useForm.
if (isValid) clearErrors()
// Check if all your inputs are filled
else if (
!isValid &&
watch('bank') &&
watch('accountType') &&
watch('accountNumber')
)
trigger()
}, [isValid])
Make sure to have your path in your schema
if (accountNumber.startsWith('10') && bank === '01')
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ['accountNumber'],
message: `Your Account number cannot start with 10`,
fatal: true,
})
return z.NEVER
following
This fix worked for me. tldr:
- path: [...ctx.path, idx, 'myProperty'],
+ path: [`[${idx}].myProperty`],
Kudos @bluebill1049 for the debug code; I wouldn't have found this issue without it. 💯
I'm running into the same issue. In my case the superRefine is needing to flag an error on a field which has not been edited. This field is only required if another field has a given value. When this happens, RHF is recognizing that the form is invalid but doesn't add the error to the field or form.
I can get around this, mostly, by using the trigger function on the form to tell RHF to validate the fields that were never edited.
You can see this in the Codesandbox link in the original error report. When you run the sandbox as-is, the form is invalid with no errors. But if you add the following at line 24 then the error message appears on the form:
form.trigger("start")
This is not quite optimal as I need to remember to call trigger to force RHF to fully recognize the validation error.
Bottom line, if superRefine is flagging an error on a field which is not dirty (not touched?), somehow add a call to trigger tied to an event on the form which tells the form to check if the field is valid. For example:
useEffect(() => {
trigger(["fieldReceivingError"]);
}, [fieldCausingError.field.value]);
Same issue here, I have an object where you need to fill in a start and end time, i have a refine on the object that checks if the start_time is before the end_time, i can throw the error on the start_time like this.
export const CreateWorkActivityRequest = object({
start_time: date(),
end_time: date(),
}).refine(
(val) => {
if (val.type !== 'travel') {
return !isAfter(val.start_time, val.end_time)
}
return true
},
{
message: 'Start tijd is later dan eind tijd',
path: ['start_time']
}
)
But i want to make use of the 'root' property in the errors so i can show the error at the end of the form like we do with server errors
setError("root.serverError", {
type: "400",
})
but throwing this error will make the form pass but the object its sending is empty
.refine(
(val) => {
if (val.type !== 'travel') {
return !isAfter(val.start_time, val.end_time)
}
return true
},
{
message: 'Start tijd is later dan eind tijd',
path: ['root', 'start_end_time_mismatch']
}
)
with superRefine
this also works
.superRefine(
(val, ctx) => {
if (val.type !== 'travel' && isAfter(val.start_time, val.end_time)) {
console.log('validation failed')
ctx.addIssue({
code: ZodIssueCode.invalid_date,
message: 'Start tijd is later dan eind tijd',
path: ['start_time'],
});
return NEVER
}
},
)
but this doenst
.superRefine(
(val, ctx) => {
if (val.type !== 'travel' && isAfter(val.start_time, val.end_time)) {
console.log('validation failed')
ctx.addIssue({
code: ZodIssueCode.invalid_date,
message: 'Start tijd is later dan eind tijd',
path: ['root', 'start_end_time_mismatch'],
});
return NEVER
}
},
)
Describe the bug I want to use zod's
superRefine
validation function. hook form shows that form is invalid, buterrors
object is emptyTo Reproduce Steps to reproduce the behavior:
isValid
isfalse
buterrors
object is emptyCodesandbox link (Required) https://stackblitz.com/edit/vitejs-vite-dwvjn3?file=src/App.jsx
Expected behavior
error
object should haveBlock is too short
error messageDesktop (please complete the following information):