Implement A DataTable using the repository.
<v-table
ref="tasks"
route="tasks/table">
<template slot="caption">
<i class="fa fa-tasks"></i> Tasks
</template>
<template slot="thead" slot-scope="table">
<th class="text-center" style="width: 60px">ID</th>
<th class="text-left" style="width: auto">Script</th>
<th class="text-left" style="width: 160px">Status</th>
<th class="text-left">Timestamp</th>
<th class="text-left">Edit</th>
</template>
<template slot="row" slot-scope="row">
<th class="text-center">@{{ row.data.id }}</th>
<td class="text-left">@{{ row.data.name }}</td>
<td class="text-left">@{{ row.data.statusLabel }}</td>
<td class="text-left">@{{ row.data.created_at }}</td>
<td class="text-left">
<a :href="`/tasks/${row.data.id}`" class="btn btn-sm">
<i class="fa fa-edit"></i> Show
</a>
</td>
</template>
</v-table>
<script>
import {Repository} from 'laravel-micro.js'
export default {
name: "Table",
props: {
route: {
type: String,
required: true,
}
},
data() {
return {
table: new Repository,
isLoading: false,
isLoaded: false,
search: '',
}
},
computed: {
rows() {
return this.table.get('data', [])
},
params() {
return {
search: this.search,
page: this.currentPage,
orderBy: this.orderedBy,
sort: this.sortedBy,
}
},
isFirstPage() {
return this.currentPage === 1
},
isLastPage() {
return this.currentPage === this.lastPage
},
sortedBy: {
get() {
return this.table.get('sort', 'desc')
},
set(val) {
this.table.set('sort', val)
this.fetch()
}
},
orderedBy: {
get() {
return this.table.get('orderBy', 'id')
},
set(val) {
this.table.set('orderBy', val)
}
},
currentPage: {
get() {
return this.table.get('current_page', 1)
},
set(val) {
this.table.set('current_page', val)
}
},
lastPage() {
return this.table.get('last_page', 1)
},
},
methods: {
sort(val) {
if (!this.isSortedBy(val)) {
this.isLoading = val
this.sortedBy = val
this.fetch()
}
},
isSortedBy(val) {
return this.sortedBy === val
},
order(val) {
if (!this.isSortedBy(val)) {
this.isLoading = val
this.orderedBy = val
this.fetch()
}
},
isOrderedBy(val) {
return this.orderedBy === val
},
nextPage() {
if (this.currentPage < this.table.get('last_page', 1)) {
this.isLoading = 'next'
this.currentPage++
this.fetch()
}
},
prevPage() {
if (this.currentPage > 1) {
this.isLoading = 'prev'
this.currentPage--
this.fetch()
}
},
fetchSearch(){
this.isLoading = 'search'
this.currentPage = 1
this.fetch()
},
async fetch() {
await this.$options.$http
.get(this.route, {
params: this.params
}).then(({data}) => {
this.table.update(data)
this.isLoaded = true
}).finally(() => {
this.isLoading = false
})
},
hasSlot(name) {
return !!this.$slots[name]
}
},
created() {
this.$options.$http = this.$app.make('Http')
this.fetch()
}
}
</script>
<template>
<div>
<div class="flex flex-wrap">
<div class="mr-1 flex flex-row">
<input
type="text"
class="search"
v-model="search"
@keydown.enter="fetchSearch"
placeholder="Search...">
<button
type="button"
@click="fetchSearch"
class="btn btn-search">
<v-loading
:size="20"
color="white"
v-if="isLoading === 'search'">
</v-loading>
<i v-else class="fa fa-search"></i>
</button>
</div>
<button
class="btn btn-sm"
@click.prevent="sort('asc')"
:disabled="isSortedBy('asc')">
<v-loading
:size="12"
color="white"
v-if="isLoading === 'asc'">
</v-loading>
<span v-else>Asc</span>
</button>
<div class="ml-1"></div>
<button
class="btn btn-sm"
@click.prevent="sort('desc')"
:disabled="isSortedBy('desc')">
<v-loading :size="12" color="white" v-if="isLoading === 'desc'"></v-loading>
<span v-else>Desc</span>
</button>
<slot
name="filters"
:sort="sort"
:table="table"
:nextPage="nextPage"
:prevPage="prevPage"
:isSortedBy="isSortedBy"
:isOrderedBy="isOrderedBy"
:isFirstPage="isFirstPage"
:isLastPage="isLastPage">
</slot>
<div class="flex flex-grow"></div>
<div class="text-gray-400 text-sm self-center">
Page {{ currentPage}} of {{lastPage}}
</div>
</div>
<div class="card shadow-xl my-3">
<div class="card-header">
<slot name="caption"></slot>
</div>
<div class=" overflow-x-auto overflow-y-hidden">
<table class="table">
<thead>
<tr>
<slot
name="thead"
:sort="sort"
:table="table"
:nextPage="nextPage"
:prevPage="prevPage"
:isSortedBy="isSortedBy"
:isOrderedBy="isOrderedBy"
:isFirstPage="isFirstPage"
:isLastPage="isLastPage">
</slot>
</tr>
</thead>
<tbody v-if="rows.length">
<tr v-for="row in rows">
<slot
name="row"
:data="row"
:sort="sort"
:table="table"
:nextPage="nextPage"
:prevPage="prevPage"
:isSortedBy="isSortedBy"
:isOrderedBy="isOrderedBy"
:isFirstPage="isFirstPage"
:isLastPage="isLastPage">
</slot>
</tr>
</tbody>
<tbody v-else-if="isLoaded">
<tr>
<td colspan="100%">
<div class="alert info">No results.</div>
</td>
</tr>
</tbody>
<tfoot v-if="hasSlot('footer')">
<tr>
<slot
name="tfoot"
:sort="sort"
:table="table"
:nextPage="nextPage"
:prevPage="prevPage"
:isSortedBy="isSortedBy"
:isOrderedBy="isOrderedBy"
:isFirstPage="isFirstPage"
:isLastPage="isLastPage">
</slot>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="flex flex-wrap">
<button
class="btn"
:disabled="isFirstPage"
@click.prevent="prevPage">
<v-loading
:size="14"
color="white"
v-if="isLoading === 'prev'">
</v-loading>
<span v-else><i class="fa fa-chevron-left"></i> Prev</span>
</button>
<div class="ml-1"></div>
<button
class="btn"
:disabled="isLastPage"
@click.prevent="nextPage">
<v-loading
:size="14"
color="white"
v-if="isLoading === 'next'">
</v-loading>
<span v-else>Next <i class="fa fa-chevron-right"></i></span>
</button>
<div class="flex flex-grow"></div>
<div class="text-gray-400 text-sm self-center">
Page {{ currentPage}} of {{lastPage}}
</div>
</div>
</div>
</template>