Reputation: 199
I am building a simple invoice system in Laravel. So obviously I need to build a view, when I will be able to edit it. It is a table, where I can dynamically add and remove rows.
So my thinking was: ok, I can do that quite easily with jQuery, but adding a row with multiple inputs, especially when I'm using tailwind, meaning having a lot of weird classes, will be messy, so I'll try with Vue. I have no experience with it, but in general it looks easy.
I made a Vue component then, which contains <table>
, and <tr>
s with inputs inside:
<document-items-table :items='@json($document->items)' />
It's not SPA, so I didn't want to make AJAX call inside, I have my document already loaded so I passed document items through a vue prop as Json. And it works fine.
Next thing is, to every document line I've added delete button which deletes a line. I've got also a button which adds an empty line.
My component looks like this:
<template>
<div class="w-full">
<div class="relative flex flex-col min-w-0 break-words w-full rounded bg-white">
<div class="block w-full overflow-x-auto">
<table class="items-center w-full bg-transparent border-collapse pb-4">
<thead>
<tr>
<th style="width: 30px" class="pl-6 pr-2 align-middle border-b border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left bg-blueGray-50 text-blueGray-500 border-blueGray-100">
No.
</th>
<th style="min-width: 600px" class=" align-middle border-b border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left bg-blueGray-50 text-blueGray-500 border-blueGray-100">
Name
</th>
<th style="width: 60px" class="align-middle border-b border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left bg-blueGray-50 text-blueGray-500 border-blueGray-100">
Quantity
</th>
<th style="width: 60px" class="align-middle border-b border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left bg-blueGray-50 text-blueGray-500 border-blueGray-100">
Unit
</th>
<th style="width: 120px" class="align-middle border-b border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left bg-blueGray-50 text-blueGray-500 border-blueGray-100">
Price
</th>
<th style="width: 60px" class="align-middle border-b border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left bg-blueGray-50 text-blueGray-500 border-blueGray-100">
Tax rate
</th>
<th style="width: 60px" class="align-middle border-b border-solid py-3 text-xs uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left bg-blueGray-50 text-blueGray-500 border-blueGray-100">
</th>
</tr>
</thead>
<tbody class="border-b-4 border-white">
<tr v-for="(item, i) in this.itemsLocal" :key="item.id">
<td class="border-t-0 pl-6 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap py-1">
{{ i + 1 }}
</td>
<td class="border-t-0 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap py-1">
<item-input name="title" id="title" :value="item.title" />
</td>
<td class="border-t-0 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap py-1">
<item-input class="w-full" name="quantity" id="quantity" :value="item.quantity" />
</td>
<td class="border-t-0 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap py-1">
<item-input class="w-full" name="unit" id="unit" :value="item.unit" />
</td>
<td class="border-t-0 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap py-1">
<item-input class="w-full" name="price" id="price" :value="item.price / 100" />
</td>
<td class="border-t-0 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap py-1">
<item-input class="w-full" name="tax" id="tax" :value="item.tax_rate" />
</td>
<td class="border-t-0 align-middle border-l-0 border-r-0 text-xs whitespace-nowrap py-1">
<button @click="() => deleteRow(item.id)" class="p-2 px-4 bg-rose-500 text-white rounded"><i class="fas fa-times fa-sm"></i> </button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="w-full text-center">
<button @click="addRow" class="bg-lightBlue-600 px-4 py-2 text-white rounded text-sm font-bold">Add row</button>
</div>
</div>
</template>
<script>
export default {
props: {
items: Array,
},
mounted() {
},
data () {
return {
itemsLocal: [...this.items],
newRowCount: 1
}
},
methods: {
deleteRow(itemID) {
this.itemsLocal = _.reject(this.itemsLocal, ['id', itemID]);
},
addRow() {
this.itemsLocal.push({
id: -this.newRowCount
})
this.newRowCount++;
}
}
}
</script>
Now I have some questions to the people more experienced with Vue
props
isn't allowed, and I need to add and remove rows, I'm cloning my items
from props
to data
and then I'm adding and deleting them. Is there a better solution for that?I try to make it as clean as possible. It's not a work project, it's rather a thing to improve my skills.
Upvotes: 1
Views: 311
Reputation: 26
Upvotes: 1