T
TanStack•7mo ago
optimistic-gold

Handling nested object validations

Hey there, im currently running into an issue with zod validations (more like a general issue). Im having a field like schema.output . output is like an object with different values object: { value: string, id: string} and i want to use the AppField object and then display the errors inside. But whenever im accessing the "top level", meaning output the errors are not there, because theyre happening on e.g. value with min(1). unless i dig into field.form.stateand extract the errors from there, i dont see any way to handle those "complex" forms. Its crucial for me, because im running into many scenarios where i need to validate an object rather than one field from the object, since theyre quite complex objects. cheers and thanks in advance 🙂
5 Replies
sensitive-blue
sensitive-blue•7mo ago
Can you get us a minimal repro? I can't quite grok what you're saying
optimistic-gold
optimistic-goldOP•7mo ago
sure, give me a moment to strip all "sensitive" data 😄
export const DefinitionInputSchema = z.object({
input: z.lazy(() => InputInputSchema.nullish()),
title: z.string().nullish(),
});
export const InputInputSchema = z.object({
portSelection: z.lazy(() => PortSelectionInputSchema),
});
export const SelectionInputSchema: = z.object({
id: z.string().min(1),
secondId: z.string().min(1)
});
export const PortSelectionInputSchema = z.object({
calculationSelection: z.lazy(() => SelectionInputSchema),
outputPortId: z.string().min(1),
});

const Form = () => {
const form = useAppForm({
validators: {
onChange: DefinitionInputSchema,
},
});
return (
<form.AppField name={"input"}>
{field => <field.FormInputSelect label="input" />}
</form.AppField>
);
};
export const getZodErrorState = (errors: unknown) => {
if (!errors || !isZodErrors(errors)) {
return { errorText: "", invalid: false };
}
const errorText = errors
?.map(error => error.message)
.filter(isTruthy)
.join(", ");
const invalid = !!errorText;
return { errorText, invalid };
};

export const FormInputSelect = ({ label }: {label:string}) => {
const field = useFieldContext<InputInputSchema["portSelection"]>();

const { errorText, invalid } = getZodErrorState(field.state.meta.errors);
return (
<Field
label={label }
errorText={errorText}
invalid={invalid}
type="select"
>
<InputSelect onSelect={field.handleChange} />
</Field>
);
};
export const DefinitionInputSchema = z.object({
input: z.lazy(() => InputInputSchema.nullish()),
title: z.string().nullish(),
});
export const InputInputSchema = z.object({
portSelection: z.lazy(() => PortSelectionInputSchema),
});
export const SelectionInputSchema: = z.object({
id: z.string().min(1),
secondId: z.string().min(1)
});
export const PortSelectionInputSchema = z.object({
calculationSelection: z.lazy(() => SelectionInputSchema),
outputPortId: z.string().min(1),
});

const Form = () => {
const form = useAppForm({
validators: {
onChange: DefinitionInputSchema,
},
});
return (
<form.AppField name={"input"}>
{field => <field.FormInputSelect label="input" />}
</form.AppField>
);
};
export const getZodErrorState = (errors: unknown) => {
if (!errors || !isZodErrors(errors)) {
return { errorText: "", invalid: false };
}
const errorText = errors
?.map(error => error.message)
.filter(isTruthy)
.join(", ");
const invalid = !!errorText;
return { errorText, invalid };
};

export const FormInputSelect = ({ label }: {label:string}) => {
const field = useFieldContext<InputInputSchema["portSelection"]>();

const { errorText, invalid } = getZodErrorState(field.state.meta.errors);
return (
<Field
label={label }
errorText={errorText}
invalid={invalid}
type="select"
>
<InputSelect onSelect={field.handleChange} />
</Field>
);
};
something like this, whereas im trying to display the error inside FormInputSelect
flat-fuchsia
flat-fuchsia•7mo ago
Maybe I can refine the question a bit. When we have a nested validation schema like DefinitionInputSchema here and we have a field that uses input.portSelection, does Tanstack Form apply the "sub"-schema InputInputSchema to this specific field validation? Because it doesn't seem to be the case. When debugging it seems the validators are missing for the field. It seems for example onMount it only validates the top-level.
optimistic-gold
optimistic-goldOP•6mo ago
@crutchcorn did you get a chance to take a look yet?
metropolitan-bronze
metropolitan-bronze•6mo ago
@JeRakaBaka by minimal repo I'm fairly certain crutchcorn ment a stackBlitz, it's rather hard to debug from a code snippet. 🤟

Did you find this page helpful?