Superforms更新对象数组:提交后端丢失新增题目数据
问题分析与解决
你遇到的核心问题是:前端通过按钮更新$form.questions后UI显示正常,但表单提交时后端收不到新增的题目数据。这是因为表单提交的数据是从DOM元素中收集的,而非直接从$form对象读取——你只是更新了状态,但没有为新增的question生成对应的表单输入字段,所以这些数据不会被包含在提交的表单里。
解决方案
1. 渲染新增题目的表单字段
需要在模板中循环遍历$form.questions,为每个question生成对应的输入控件,并设置正确的name属性(Superforms会通过这个属性关联到$form的对应值)。
2. 修改前端代码示例
更新你的Svelte组件,添加题目渲染部分:
<script lang="ts"> const { form, errors, constraints, enhance } = superForm<ExamSchema, any, any>(data.form); </script> <form enctype="multipart/form-data" method="POST" use:enhance> <!-- 新增题目按钮 --> <button type="button" onclick={() => { const newQuestion: ExamSchema['questions'][0] = { id: shortUUID.uuid(), type: 'abc', points: '0', question: '', answers: [], }; $form.questions = [...$form.questions, newQuestion]; }} class="toolbar-btn" > <Abc height="16px" width="16px"></Abc> 添加题目 </button> <!-- 渲染所有题目 --> {#each $form.questions as question, index} <div class="question-container"> <h4>题目 {index + 1}</h4> <!-- 题目类型 --> <input type="text" name={`questions[${index}].type`} bind:value={question.type} placeholder="题目类型" /> <!-- 题目分值 --> <input type="text" name={`questions[${index}].points`} bind:value={question.points} placeholder="分值" /> <!-- 题目内容 --> <textarea name={`questions[${index}].question`} bind:value={question.question} placeholder="题目内容" ></textarea> <!-- 如果有answers字段,也需要渲染对应的输入 --> {#each question.answers as answer, ansIndex} <input type="text" name={`questions[${index}].answers[${ansIndex}]`} bind:value={answer} placeholder="选项" /> {/each} </div> {/each} <button type="submit" class="button-primary save-exam"> {$i18n.t('teacher_panel.exam_editor.submit')} </button> </form>
关键说明
- 每个表单字段的
name属性必须遵循questions[索引].字段名的格式,比如questions[0].type,这样Superforms才能正确将DOM值与$form.questions中的对应元素关联。 - 使用
bind:value确保输入值与$form状态双向同步,这样你修改输入时$form会自动更新,反之更新$form时输入也会同步。 - 即使是初始为空的字段(比如
question、answers),也需要渲染对应的DOM元素,否则提交时这些字段不会被包含在表单数据中。
验证后端
后端代码目前是正确的,只要前端提交的表单数据包含questions数组,superValidate会自动解析并验证。你可以在后端打印request.formData()来确认是否收到数据:
export const actions = { default: async (request) => { const formData = await request.formData(); console.log('表单数据:', Object.fromEntries(formData)); // 检查是否有questions相关字段 const form = await superValidate(request, zod(examSchema)); console.log('验证后的数据:', form); return { form }; } } satisfies Actions;
内容的提问来源于stack exchange,提问作者Marcin
相关产品推荐
相关产品推荐

