0

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 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, index) 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" :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 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 { 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.

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your response @Daniel, following your suggestions solved my problem. I better understand how the template section works in relation to the script section from realising that my hidden input elements where unnecessary. This code gives me the inputs I need at the backend from each button click: ` function payPerformanceFee(index) { const form = useForm({ amount: bills.value[index].amount, goal_id: bills.value[index].goal_id }) form.post(route('pending.bill')) }` Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.