Laravel Vue Datatable
A Vue.js datatable component for Laravel that works with Bootstrap.
Requirements
- Vue.js 2.x
- Laravel 5.x
- Bootstrap 4 (Optional)
This package makes use of an optional default component, the Laravel Vue Pagination component created by gilbitron. If you need a pagination component for other areas of your website and you are using a Laravel API & Bootstrap, i highly suggest using this flexible component.
Package Installation
See details https://github.com/jamesdordoy/Laravel-Vue-Datatables
Component Installation
$ npm install laravel-vue-datatable
Register the Plugin
import DataTable from 'laravel-vue-datatable';
Vue.use(DataTable);
Basic Example
UserDatatable.vue
<data-table
url="http://vue-datatable.test/ajax"
:per-page="perPage"
:columns="columns">
</data-table>
export default {
name: 'app',
data() {
return {
perPage: ['10', '25', '50'],
columns: [
{
label: 'ID',
name: 'id',
filterable: true,
},
{
label: 'Name',
name: 'name',
filterable: true,
},
{
label: 'Email',
name: 'email',
filterable: true,
},
{
label: '',
name: 'View',
filterable: false,
},
]
}
},
}
API
Datatable Props
Name | Type | Default | Description |
---|---|---|---|
url |
String | "/" | The JSON url |
columns |
Array | [] | The table columns |
per-page |
Array | [ '10', '25', '50' ] | (optional) Amount to be displayed |
classes |
Object | See Below | (optional) Table classes |
pagination |
Object | {} | (optional) props for gilbitron/laravel-vue-pagination |
Default Classes
{
"table-container": {
"table-responsive": true,
},
"table": {
"table": true,
"table-striped": true,
"table-dark": true,
},
"t-head": {
},
"t-body": {
},
"t-head-tr": {
},
"t-body-tr": {
},
"td": {
},
"th": {
},
}
Column Props
Name | Type | Default | Description |
---|---|---|---|
label |
String | "" | The JSON url |
name |
String | "" | The table column header name |
width |
Number | 0 | The table column width |
filterable |
Boolean | false | Is the column filterable |
component |
Component | null | A dynamic component that can be injected |
classes |
Object | {} | Component classes to parse |
Using Dynamic Components
You can also inject your own components into the table such as buttons. Your buttons, links etc can also listen for events.
Example Button Component
(ExampleButton.vue)
<template>
<button :class="classes" @click="click(data)" title="Update">
<span>
<i class="fa fa-eye" aria-hidden="true"></i>
</span>
{{ name }}
</button>
</template>
export default {
props: {
data: {},
name: {},
click: {},
classes: {},
}
}
Dynamic Datatable Columns
(UserDatatable.vue)
import ExampleButton './ExampleButton.vue';
export default {
data() {
return {
url: 'http://vue-datatable.test/ajax',
perPage: ['10', '25', '50'],
columns: [
{
label: 'ID',
name: 'id',
filterable: true,
},
{
label: 'Name',
name: 'name',
filterable: true,
},
{
label: 'Email',
name: 'email',
filterable: true,
}
{
label: '',
name: 'View',
filterable: false,
component: ExampleButton,
event: "click",
handler: this.alertMe,
classes: {
'btn': true,
'btn-primary': true,
'btn-sm': true,
}
},
]
}
},
components: {
// eslint-disable-next-line
ExampleButton,
},
methods: {
alertMe(data) {
alert("hey");
}
},
}
Overriding the Filters and Pagination Components
If the included pagination or filters do not meet your requirements or if the styling is incorrect, they can be over-written using scoped slots.
Paginatior Datatable
<data-table
:url="url"
:columns="columns"
:per-page="perPage">
<span slot="pagination" slot-scope="{ links, meta }">
<paginator
:meta="meta"
:links="links"
@next="updateUrl"
@prev="updateUrl">
</paginator>
</span>
</data-table>
Once the URL has been updated by your customer paginator or filters, the table will re-render. Alterativly, if updating the URL is troublesome, different table filters can be manipulated by your filters using the v-model directive:
Example Filter
(DatatableFilter.vue)
This example filter will control the length of the table manipulating the tableData.length property using v-model.
<template>
<select
class="form-control"
v-model="tableData.length">
<option
:key="index"
:value="records"
v-for="(records, index) in perPage">
{{ records }}
</option>
</select>
</template>
export default {
props: [
"tableData", "perPage"
]
}
Filter Datatable
<data-table
:url="url"
:columns="columns"
:per-page="perPage">
<span slot="filters" slot-scope="{ tableData, perPage }">
<data-table-filters
:per-page="perPage"
:table-data="tableData">
</data-table-filters>
</span>
</data-table>
Custom Filters
You can also add your own custom filters to be sent to the Laravel backend:
Datatable
data() {
return {
url: "/url",
perPage: ['10', '25', '50'],
columns: [
...
],
filters: {
isAdmin: '',
},
pagination:{
limit: 1,
align: "right",
size: "small"
}
}
},
<data-table
:url="url"
:filters="filters"
:columns="columns"
:per-page="perPage"
:pagination="pagination">
<span slot="filters" slot-scope="{ tableData, perPage }">
<data-table-filters
:table-data="tableData"
:per-page="perPage">
</data-table-filters>
</span>
</data-table>
Example Filter
<div class="row mb-3">
<div class="col-md-3">
<select
v-model="tableData.length"
class="form-control">
<option
:key="index"
:value="records"
v-for="(records, index) in perPage">
{{records}}
</option>
</select>
</div>
<div class="col-md-3">
<select
v-model="tableData.filters.isAdmin"
class="form-control">
<option value>All Staff</option>
<option value='admin'>Admin</option>
<option value='staff'>Staff</option>
</select>
</div>
<div class="col-md-3 offset-md-3">
<input
name="name"
class="form-control"
v-model="tableData.search"
placeholder="Search Table">
</div>
</div>
This added "isAdmin" filter for staff type will be send to the Laravel backend and can be used to manipulate the results:
$query = User::dataTableQuery($column, $dir, $length, $searchValue);
if (isset($isAdmin) && ! empty($isAdmin)) {
$query->where("type", $isAdmin);
}
$data = $query->paginate($length);
return new DataTableCollectionResource($data);
Styling the Datatable
You can edit the style of the Datatable by overriding the classes
prop. A example mixin config can be found be below for Tailwind:
Tailwind Config
(mixins/tailwind.js)
Custom Class
.stripped-table:nth-child(even) {
@apply bg-black;
}
export default {
data() {
return {
classes: {
'table-container': {
'justify-center': true,
'w-full': true,
'flex': true,
'rounded': true,
'mb-6': true,
'shadow-md': true,
},
table: {
'text-left': true,
'w-full': true,
'border-collapse': true,
},
't-head': {
'text-grey-dark': true,
'bg-black': true,
'border-grey-light': true,
'py-4': true,
'px-6': true,
},
"t-body": {
'bg-grey-darkest': true,
},
"t-head-tr": {
},
"t-body-tr": {
'stripped-table': true,
'bg-grey-darkest': true,
},
"td": {
'py-4': true,
'px-6': true,
'border-b': true,
'border-grey-light': true,
'text-grey-light': true,
},
"th": {
'py-4': true,
'px-6': true,
'font-bold': true,
'uppercase': true,
'text-sm': true,
'text-grey-dark': true,
'border-b': true,
'border-grey-light': true,
},
}
};
},
}
Tailwind Datatable
<data-table
:url="url"
:columns="columns"
:classes="classes"
:per-page="perPage">
<span slot="filters" slot-scope="{ tableData, perPage }">
<data-table-filters
:table-data="tableData"
:per-page="perPage">
</data-table-filters>
</span>
<span slot="pagination" slot-scope="{ links, meta }">
<paginator
@next="updateUrl"
@prev="updateUrl"
:meta="meta"
:links="links">
</paginator>
</span>
</data-table>
import TailwindDatatable from '../mixins/tailwind.js';
export default {
data() {
return {
url: 'http://vue-datatable.test/ajax',
perPage: ['10', '25', '50'],
columns: [
{
label: 'ID',
name: 'id',
filterable: true,
},
{
label: 'Name',
name: 'name',
filterable: true,
},
{
label: 'Email',
name: 'email',
filterable: true,
}
]
}
},
mixins: [
TailwindDatatable
]
}
Development
To work on the library locally, run the following command:
npm run serve
To run the tests:
npm run test