Vue中如何处理含多内嵌表单行的表格及Inertia表单绑定问题
问题根因
- 你仅创建了1个全局共享的Inertia form实例,v-for渲染的所有行表单都绑定到这同一个实例,无法区分不同行的账单数据
bills.value是后端返回的账单数组,数组本身不存在amount、goal_id属性,直接读取这两个值必然返回undefined- 循环渲染的隐藏input存在全局id重复问题,且你没有把每行对应的账单值和表单做对应绑定,提交时自然拿不到正确数据
- 你重复定义了两次账单数据源:既通过
defineProps声明接收父组件传入的pendingBills,又通过usePage重复从页面props取数,容易造成数据源混乱
实现方案
不需要为每一行单独创建form实例(会造成不必要的内存开销),保留单个form实例即可,提交时直接传入当前行的账单数据赋值给form,天然满足「同一时间仅能触发一个提交」的需求,具体改动如下:
- 移除循环内冗余的重复id隐藏input(Inertia useForm提交时直接读取响应式对象的字段值,不需要依赖DOM input元素传值)
- 初始化form时不需要提前绑定账单数据,字段留空即可
- 提交事件直接传入当前循环的bill对象,在提交逻辑内给form字段赋值后再发起请求
- 统一使用单一数据源,去掉重复的账单数据读取逻辑
修正后完整代码
<template> <jet-action-section> <template #title> Pending Bills </template> <template #description> A list of all pending payments. </template> <template #content> <h3 class="text-sm font-medium text-gray-900 dark:text-gray-200" v-if="pendingBills.length > 0"> Pending Payments. </h3> <div class="mt-3 max-w-xl text-sm text-gray-600 dark:text-gray-300" v-if="pendingBills.length > 0"> <div class="p-6 overflow-x-auto"> <table class="w-full whitespace-nowrap"> <tr class="text-left font-bold text-white"> <th class="bg-blue-500 border-4 p-2 rounded">Payment Description</th> <th class="bg-blue-500 border-4 p-2 rounded">Amount</th> <th class="bg-blue-500 border-4 p-2 rounded">Action</th> </tr> <tr v-for="bill in pendingBills" :key="bill.id" class="text-gray-700 dark:text-gray-200 hover:bg-blue-200 dark:hover:bg-blue-300 focus-within:bg-blue-100"> <td class="border-2 p-2">{{ bill.message }}</td> <td class="border-2 p-2">₦{{ bill.amount }}</td> <td class="border-2 p-2"> <form @submit.prevent="payPerformanceFee(bill)"> <div class="flex items-center justify-end mt-4"> <jet-button class="ml-4" :class="{ 'opacity-25': form.processing }" :disabled="form.processing"> Pay Performance Fee </jet-button> </div> </form> </td> </tr> </table> </div> </div> <h3 class="text-sm font-medium text-gray-900 dark:text-gray-200" v-else> Payments you're yet to pay will show up here. </h3> </template> </jet-action-section> </template> <script setup> import JetActionSection from '@/Jetstream/ActionSection.vue' import JetButton from '@/Jetstream/Button.vue' import { useForm } from '@inertiajs/inertia-vue3' // 统一使用父组件传入的pendingBills作为数据源,若数据是从Inertia页面props传入则替换为usePage读取逻辑即可 const props = defineProps({ pendingBills: { type: Array, required: true } }) const form = useForm({ amount: null, goal_id: null }) function payPerformanceFee(bill) { // 提交前给form字段赋值当前行的账单数据 form.amount = bill.amount form.goal_id = bill.goal_id form.post(route('pending.bill')) } </script>
说明:因为全局只有一个form实例,提交时
form.processing会变为true,所有行的支付按钮都会自动进入禁用状态,天然避免重复提交,完全符合需求。
内容的提问来源于stack exchange,提问作者Adefowowe
相关产品推荐
相关产品推荐

