A Vue.js datatable component for Laravel that works with Bootstrap

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>
        &nbsp;
        {{ 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

GitHub