T
TanStack•7mo ago
absent-sapphire

Conditional fields and validation?

https://stackblitz.com/edit/tanstack-form-gecmjp4w?file=src%2Findex.tsx How to handle conditional fields, when visible is false, lastName should not validate here.
Keelan
StackBlitz
Form Standard Schema Example (forked) - StackBlitz
Run official live example code for Form Standard Schema, created by Tanstack on StackBlitz
18 Replies
foreign-sapphire
foreign-sapphire•7mo ago
I think you'd be better off explicitly setting lastName to nullable or optional. Doing something like this: You can also do discriminated unions if needed, but that'd be overkill for something this simple. See example here: https://stackblitz.com/edit/tanstack-form-zd9iccna?file=src%2Findex.tsx
juanvilladev
StackBlitz
Form Standard Schema Example (forked) - StackBlitz
Run official live example code for Form Standard Schema, created by Tanstack on StackBlitz
foreign-sapphire
foreign-sapphire•7mo ago
Note the listener that sets lastName to null onChange if visible is false, this is key.
absent-sapphire
absent-sapphireOP•7mo ago
Oh, that's great, thank you! I'll mess about with this with the issue I'm having tomorrow, hopefully this fixes it. Thanks so much!
foreign-sapphire
foreign-sapphire•7mo ago
You're welcome 😄
absent-sapphire
absent-sapphireOP•7mo ago
Sorry to ask another Q, I've just been messing around a bit with it, how would I do that type of refining on a field-basis (where I don't use a schema for the validation) I suppose this is more of a Zod Q. https://stackblitz.com/edit/tanstack-form-syy1n5ms?file=src%2Findex.tsx
Keelan
StackBlitz
Form Standard Schema Example (forked) - StackBlitz
Run official live example code for Form Standard Schema, created by Tanstack on StackBlitz
foreign-sapphire
foreign-sapphire•7mo ago
If you're depending on other fields, you can't directly add a refine the the subfield. For this reason you see that i added the refine at the object level. You can, however, set a refine on the object level and target a field in the object for error placement. You can see I set the path on the refine to point to one of the fields.
absent-sapphire
absent-sapphireOP•7mo ago
So if I move to the field level I can't have a dependency on another field?
<form.Field
name="lastName"
validators={{
onSubmit: z
.string()
.min(3, '[Zod] You must have a length of at least 3')
.nullable(),
// TODO: if visible is true
}}
>
<form.Field
name="lastName"
validators={{
onSubmit: z
.string()
.min(3, '[Zod] You must have a length of at least 3')
.nullable(),
// TODO: if visible is true
}}
>
foreign-sapphire
foreign-sapphire•7mo ago
I meant if you have a form level schema, you'd have to refines on the zod schema itself. If you want to have zod schemas at the field level, you can also use refine, however note you can pass in a function that returns a schema. The parameters for the onSubmit allow you to grab the fieldApi, which you can use to grab other field values! Does that make sense? So then you can build the schema on the fly.
absent-sapphire
absent-sapphireOP•7mo ago
Yes, I think I got it! Thanks again. https://stackblitz.com/edit/tanstack-form-syy1n5ms?file=src%2Findex.tsx Just one last question, if I immediately press "Submit", I get an error as expected on lastName, but I cannot clear that error even if I change visible to false, I can no longer submit. Is there something I can do to reset the form errors?
Keelan
StackBlitz
Form Standard Schema Example (forked) - StackBlitz
Run official live example code for Form Standard Schema, created by Tanstack on StackBlitz
foreign-sapphire
foreign-sapphire•7mo ago
I think this might be related to the issue I've been posting about in #form For now you'd need to trigger (validate) the lastName field somehow...
absent-sapphire
absent-sapphireOP•7mo ago
Oh I see, if you’re experiencing similar things that’s all good then. Thanks again To be honest, I don’t know why fields that are not in the DOM are even validated
foreign-sapphire
foreign-sapphire•7mo ago
It’s because the library doesn’t necessarily depend on the DOM, it’s how we also achieve the ability to work cross frameworks like React and so on! I think it’s a bit better that way you have less implicit behavior you can’t control
xenial-black
xenial-black•7mo ago
For field level validations it's not my experience at all that fields that are not mounted are being validated, it's the fieldMeta is not being cleared out so existing errors prevent the form from submitting. You would have to manually reset the fieldMeta when you unmount the field.
absent-sapphire
absent-sapphireOP•7mo ago
Oh, interesting, I'll keep that in mind when I take a look later. I assume there is a function for that. Thanks!
xenial-black
xenial-black•7mo ago
yes there is setFieldMeta on the form api. IMO it would be great if the library could somehow do this by default.
absent-sapphire
absent-sapphireOP•7mo ago
For me it’s still coming up with an error even when I set the fieldMeta, I must be using it wrong For me it just keeps the same values somehow before and after reset
fascinating-indigo
fascinating-indigo•7mo ago
It's this 100%. Not only does the DOM detachment allow us to support UI components and RN, but it also enables hidden inputs et al We did in the past and removed it because it was much harder to reason about for a FW agnostic library like ours. We're adding the ability to make custom form.Field components soon, and you can easily add a cleanup on a useEffect to remove values in that setup
absent-sapphire
absent-sapphireOP•5mo ago
Okay I’ll wait on that then, thanks I’ve had some success with this in the mean time: export const createConditionalValidator = ( fieldName: string, validator: ZodType, falsy?: boolean, ) => { return ({ value, fieldApi, }: { value: unknown; fieldApi: FieldApi<any, any, any, any, any>; // eslint-disable-line @typescript-eslint/no-explicit-any }) => { const fieldValue = fieldApi.form.getFieldValue(fieldName); const isEmpty = Array.isArray(fieldValue) ? fieldValue.length === 0 : !fieldValue; const isConditionMet = falsy ? isEmpty : !isEmpty; if (isConditionMet) { const parseResult = validator.safeParse(value); if (!parseResult.success) { return parseResult.error.errors[0].message; } } return undefined; }; }; This is from a long time ago but this worked for me now in v1

Did you find this page helpful?