Home > Mobile >  How do I correctly handle this table with multiple embedded form rows in vue?
How do I correctly handle this table with multiple embedded form rows in vue?

Time:07-05

I have this table where I loop through data from the backend. One of the rows contain a form with hidden input fields.

The table displays properly but the input fields are not bound to the form.

This is the SFC for the page:

<template>
    <jet-action-section>
        <template #title>
            Pending Bills
        </template>

        <template #description>
            A list of all pending payments.
        </template>

        <template #content>
            <h3  v-if="pendingBills.length > 0">
                Pending Payments.
            </h3>

            <div  v-if="pendingBills.length > 0">
                <div >
                    <table >
                        <tr >
                            <th >Payment Description</th>
                            <th >Amount</th>
                            <th >Action</th>
                        </tr>
                        <tr v-for="(bill, index) in pendingBills" :key="bill.id" >
                            <td >{{ bill.message }}</td>
                            <td >₦{{ bill.amount }}</td>
                            <td  :id="bill.id">
                                <form @submit.prevent="payPerformanceFee(index)">
                                    <input id="amount" type="hidden" v-model="form.amount" />
                                    <input id="goal_id" type="hidden" v-model="form.goal_id" />
                                    <div >
                                        <jet-button  : :disabled="form.processing">
                                            Pay Performance Fee
                                        </jet-button>
                                    </div>
                                </form>
                            </td>
                        </tr>
                    </table>
                </div>
            </div>
            <h3  v-else>
                Payments you're yet to pay will show up here.
            </h3>
        </template>
    </jet-action-section>
</template>

<script setup>
import { computed } from 'vue'
import JetActionSection from '@/Jetstream/ActionSection.vue'
import Pagination from '@/Jetstream/Pagination.vue'
import JetButton from '@/Jetstream/Button.vue'
import { useForm , usePage} from '@inertiajs/inertia-vue3'


defineProps({pendingBills: Object})

const bills = computed(() => usePage().props.value.pendingBills)
console.log(bills.value) //this returns all the data from the backend

bills.value.forEach((value, index) => {
    const amount = value.amount
    const goal_id = value.goal_id
    console.log(goal_id) //this gives the expected values
    console.log(amount) //this gives the expected values
})

const form = useForm({
    amount: bills.value.amount, //this show up as undefined in vue dev tools
    goal_id: bills.value.goal_id //this show up as undefined in vue dev tools
    
})

function payPerformanceFee(index) {
    form.post(route('pending.bill'))
}
</script>

The page displays like this: Page screenshot

When I click on the button, it hits the backend with no data.

What I'm trying to achieve is to map amount and goal_id values to the corresponding inertia form so that the data is sent to the backend when the button is clicked. Obviously only one button can be clicked at a time.

I got stuck at the foreach loop. I don't know how to pass each loop cycle data to the inertia form or if I'm going about this the correct way.

CodePudding user response:

I would suggest not using the <form> element. This is helpful when you're building forms without a frontend framework, but unless you want a fallback to work without js and using a framework this can get into the way.

Anothe issue I see is that you're using <input id="amount" type="hidden" v-model="form.amount" /> in a loop. ids are meant to be unique, yet your code would generate multiple, so if you're doing a lookup by id, it will return the first one every time.

But, it looks like the id is not even being called. You're using v-model="form.amount" and v-model="form.goal_id", where form is:

const form = useForm({
    amount: bills.value.amount, //this show up as undefined in vue dev tools
    goal_id: bills.value.goal_id //this show up as undefined in vue dev tools 
})

The form is shared between every instance in each of the table rows, so the form.amount would be same for each. bill

when you call payPerformanceFee and pass it the index, it is unused by the method, so another way it is not behaving as you might want it to.

function payPerformanceFee(index) {
    form.post(route('pending.bill'))
}

You may have better luck if you just use the bills.value with the index

And in the script move the form const definition into the payPerformanceFee method

function payPerformanceFee(index) {
  const form = useForm({
    amount: bills.value[index].amount, //this show up as undefined in vue dev tools
    goal_id: bills.value[index].goal_id //this show up as undefined in vue dev tools  
  })
  form.post(route('pending.bill'))
}

In the table, because they are hidden anyway, no need to include the <input> elements.

Note that in this case, it expects the indexes to match (ie 6th row in table needs to match 6th object in bills.value) which may not be the case if the table can be sorted. If the index cannot be relied upon, you may need to use another id/key either from the data or define in component.

  • Related