如何在NuxtUI中配置UForm和UFormGroup实现嵌套动态表单错误提示
动态嵌套表单错误提示不显示的解决方法
问题场景
我用Vue 3 + Zod构建了一个动态训练表单,支持添加训练日和每个训练日的训练项目。一级字段(如name)能自动显示错误提示,但嵌套的day、exerciseName字段无法触发错误提示。虽然通过schema.parse(state)能捕获到Zod错误(包含字段路径信息),但表单组件不会自动关联这些错误到对应的输入框。
我的表单代码:
<template> <div> <h1>Training Form</h1> </div> <UForm :state="state" :schema="schema" @submit="handleSubmit"> <UFormGroup label="Name" name="name"> <UInput v-model="state.name" /> </UFormGroup> <UFormGroup label="Training Week" name="trainingWeek"> <div v-for="(day, index) in state.trainingWeek" :key="index"> <UFormGroup label="Day" name="trainingWeek[' + index + '].day"> <UInput v-model="day.day" /> </UFormGroup> <UFormGroup label="Exercises" name="trainingWeek[' + index + '].exercises"> <div v-for="(exercise, exerciseIndex) in day.exercises" :key="exerciseIndex"> <UInput v-model="exercise.exerciseName" /> </div> </UFormGroup> <div class="mt-4 flex justify-end"> <UButton @click="addExercise(index)">Add Exercise</UButton> </div> </div> </UFormGroup> <div class="mt-4 flex justify-end"> <UButton @click="addDay">Add Day</UButton> <UButton type="submit">Submit</UButton> </div> </UForm> </template> <script setup lang="ts"> import { z } from "zod"; import type { FormSubmitEvent } from "#ui/types"; const state = reactive({ name: "", trainingWeek: [ { day: "", exercises: [ { exerciseName: "", }, ], }, ], }); const schema = z.object({ name: z.string().min(1, "Required field"), trainingWeek: z.array( z.object({ day: z.string().min(1, "Required field"), exercises: z.array( z.object({ exerciseName: z.string().min(1, "Required field"), }), ), }), ), }); type Schema = z.infer<typeof schema>; const handleSubmit = (event: FormSubmitEvent<Schema>) => { console.log(JSON.stringify(event.data, null, 2)); }; const addExercise = (index: number) => { state.trainingWeek[index].exercises.push({ exerciseName: "" }); }; const addDay = () => { state.trainingWeek.push({ day: "", exercises: [{ exerciseName: "" }] }); }; </script>
捕获到的Zod错误示例:
ZodError: [ { "code": "too_small", "minimum": 1, "type": "string", "inclusive": true, "exact": false, "message": "Required field", "path": [ "trainingWeek", 0, "day" ] }, { "code": "too_small", "minimum": 1, "type": "string", "inclusive": true, "exact": false, "message": "Required field", "path": [ "trainingWeek", 0, "exercises", 0, "exerciseName" ] } ]
解决步骤
1. 修正UFormGroup的name属性格式
当前嵌套字段的name写法存在语法错误,表单组件需要正确的数组索引+点路径格式来关联字段与错误信息。改成模板字符串的正确写法:
- 训练日字段:
name="trainingWeek[${dayIndex}].day" - 训练项目字段:为每个exercise单独包裹
UFormGroup,指定路径:name="trainingWeek[${dayIndex}].exercises[${exerciseIndex}].exerciseName"
修正后的模板核心部分:
<UFormGroup label="Training Week" name="trainingWeek"> <div v-for="(day, dayIndex) in state.trainingWeek" :key="dayIndex"> <!-- 修正训练日的name属性 --> <UFormGroup label="Day" :name="`trainingWeek[${dayIndex}].day`"> <UInput v-model="day.day" /> </UFormGroup> <!-- 为每个训练项目单独设置UFormGroup --> <div class="mt-3"> <label class="block text-sm font-medium text-gray-700">Exercises</label> <div v-for="(exercise, exerciseIndex) in day.exercises" :key="exerciseIndex" class="mt-2"> <UFormGroup :name="`trainingWeek[${dayIndex}].exercises[${exerciseIndex}].exerciseName`" label="Exercise Name" > <UInput v-model="exercise.exerciseName" /> </UFormGroup> </div> </div> <div class="mt-4 flex justify-end"> <UButton @click="addExercise(dayIndex)">Add Exercise</UButton> </div> </div> </UFormGroup>
2. 开启实时验证(可选)
如果需要在输入过程中实时显示错误,可以给UForm添加validate-on="input"属性,触发输入时自动验证:
<UForm :state="state" :schema="schema" @submit="handleSubmit" validate-on="input">
3. 手动映射错误(兜底方案)
如果组件仍未自动关联错误,可以手动捕获Zod错误并映射到响应式错误对象中:
import { ZodError } from "zod"; const errors = reactive<Record<string, string>>({}); watchEffect(() => { try { schema.parse(state); // 验证通过时清空错误 Object.keys(errors).forEach(key => delete errors[key]); } catch (error) { if (error instanceof ZodError) { Object.keys(errors).forEach(key => delete errors[key]); // 将Zod的路径数组转为点格式字段名 error.issues.forEach(issue => { const fieldPath = issue.path.join("."); errors[fieldPath] = issue.message; }); } } });
然后在UFormGroup中手动绑定错误:
<UFormGroup :name="`trainingWeek[${dayIndex}].day`" label="Day" :error="errors[`trainingWeek.${dayIndex}.day`]" >
关键说明
- 表单组件依赖
name属性的路径与Zod Schema结构完全匹配,才能自动关联错误信息。 - 每个需要验证的输入框必须包裹在对应的
UFormGroup中,确保错误提示能正确挂载。 - 实时验证会带来一定性能开销,可根据场景选择
input/blur/submit等验证时机。
内容的提问来源于stack exchange,提问作者Adharsh M
相关产品推荐
相关产品推荐

