├── .editorconfig
├── .env
├── .github
├── FUNDING.yml
└── test.yml
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── __tests__
├── App.test.js
├── DataTable.test.js
├── DataTableCell.test.js
├── DataTableFilters.test.js
├── DataTableHeader.test.js
├── Table.test.js
└── bootstrap.js
├── babel.config.js
├── docs
├── 404.html
├── css
│ ├── app.4397df0e.css
│ └── chunk-vendors.872b69a4.css
├── index.html
└── js
│ ├── app.4a34b8cf.js
│ ├── app.4a34b8cf.js.map
│ ├── chunk-vendors.50daf35e.js
│ └── chunk-vendors.50daf35e.js.map
├── documentation
├── App.vue
├── assets
│ └── styles
│ │ └── main.css
├── components
│ ├── Header.vue
│ └── Navbar.vue
├── example-components
│ ├── DataTableAnchorCell.vue
│ ├── DataTableButtonCell.vue
│ ├── DataTableCurrencyCell.vue
│ ├── DataTableDateCell.vue
│ ├── DataTableDropdownCell.vue
│ ├── DataTableImageCell.vue
│ ├── DataTableIsActiveCell.vue
│ ├── DataTableListCell.vue
│ ├── DataTableNameAndImageCell.vue
│ ├── DataTableSelectCell.vue
│ ├── InformationAlert.vue
│ ├── Modal.vue
│ ├── ModalButton.vue
│ └── Switch.vue
├── filters
│ ├── format-date.ts
│ └── pad-digit.ts
├── main.ts
├── markdown
│ ├── events
│ │ └── table.md
│ ├── examples
│ │ ├── basic.md
│ │ ├── crud.md
│ │ ├── custom-filters.md
│ │ ├── injecting-dynamic-components.md
│ │ ├── joins-js.md
│ │ ├── joins-php.md
│ │ ├── loading-animations.md
│ │ ├── modal.md
│ │ ├── override-filters-and-pagination.md
│ │ ├── override-table-body.md
│ │ ├── override-table-header.md
│ │ ├── own-data.md
│ │ ├── relationships
│ │ │ ├── belongs-to-js.md
│ │ │ ├── belongs-to-many-js.md
│ │ │ ├── belongs-to-many-php.md
│ │ │ ├── belongs-to-php.md
│ │ │ ├── has-many-js.md
│ │ │ ├── has-many-php.md
│ │ │ ├── introduction.md
│ │ │ └── mysql-config.md
│ │ ├── reloading-the-table.md
│ │ ├── styling.md
│ │ └── tailwind.md
│ ├── install.md
│ ├── introduction.md
│ ├── laravel
│ │ ├── adding-trait.md
│ │ ├── controller-resource.md
│ │ ├── install.md
│ │ └── options.md
│ └── props
│ │ ├── cell.md
│ │ ├── column.md
│ │ └── table.md
├── mixins
│ ├── CodeExample.js
│ ├── CorrectTableStyling.js
│ └── CorrectTextStyling.js
├── mutations.ts
├── routes.ts
├── state.ts
└── views
│ ├── Install.vue
│ ├── Introduction.vue
│ ├── Soon.vue
│ ├── events
│ └── Table.vue
│ ├── examples
│ ├── Basic.vue
│ ├── CRUD.vue
│ ├── CustomFilters.vue
│ ├── InjectingDynamicComponents.vue
│ ├── Joins.vue
│ ├── LoadingAnimations.vue
│ ├── Modal.vue
│ ├── OverrideFiltersAndPagination.vue
│ ├── OverrideTableBody.vue
│ ├── OverrideTableHeader.vue
│ ├── ReloadingTheTable.vue
│ ├── Styling.vue
│ ├── Tailwind.vue
│ ├── UsingYourOwnData.vue
│ └── relationships
│ │ ├── BelongsTo.vue
│ │ ├── BelongsToMany.vue
│ │ ├── HasMany.vue
│ │ └── Introduction.vue
│ ├── laravel
│ ├── AddingTrait.vue
│ ├── ControllerResource.vue
│ ├── Install.vue
│ └── Options.vue
│ └── props
│ ├── Cell.vue
│ ├── Column.vue
│ └── Table.vue
├── editor.conf
├── jest.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── 404.html
└── index.html
├── src
├── components
│ ├── DataTable.vue
│ ├── DataTableCell.vue
│ ├── DataTableFilters.vue
│ ├── DataTableTh.vue
│ └── Table.vue
├── functions
│ └── MergeClasses.ts
├── mixins
│ └── UrlFilters.js
├── plugin.ts
├── shims-tsx.d.ts
├── shims-vue.d.ts
├── themes
│ ├── Bootstrap.ts
│ └── Tailwind.ts
└── validators
│ ├── data-table-framework.ts
│ ├── data-table-order-dir.ts
│ └── data-table-theme.ts
├── tailwind.config.js
├── tsconfig.json
└── vue.config.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # top-most EditorConfig file
2 | root = true
3 |
4 | # Unix-style newlines with a newline ending every file
5 | [*]
6 | end_of_line = lf
7 | insert_final_newline = true
8 |
9 | # Matches multiple files with brace expansion notation
10 | # Set default charset
11 | [*.{js,py}]
12 | charset = utf-8
13 |
14 | # 4 space indentation
15 | [*.js,*.vue ]
16 | indent_style = space
17 | indent_size = 4
18 |
19 | # Tab indentation (no size specified)
20 | [Makefile]
21 | indent_style = tab
22 |
23 | # Indentation override for all JS under lib directory
24 | [lib/**.js]
25 | indent_style = space
26 | indent_size = 4
27 |
28 | # Matches the exact files either package.json or .travis.yml
29 | [{package.json,.travis.yml}]
30 | indent_style = space
31 | indent_size = 2
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | VUE_APP_PIVOT_URL=
2 | VUE_APP_ELOQUENT_URL=
3 | VUE_APP_QUERY_BUILDER_URL=
4 | VUE_APP_DATATABLE_URL_SEARCH=
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [jamesdordoy]
--------------------------------------------------------------------------------
/.github/test.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Vue Test Utils - Jest
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | matrix:
19 | node-version: [14.x]
20 |
21 | steps:
22 | - uses: actions/checkout@v2
23 | - name: Use Node.js ${{ matrix.node-version }}
24 | uses: actions/setup-node@v1
25 | with:
26 | node-version: ${{ matrix.node-version }}
27 | - run: npm ci
28 | - run: npm run build --if-present
29 | - run: npm run test
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # prod env files
10 | .env.production
11 | .env.*.production
12 |
13 | # Log files
14 | npm-debug.log*
15 | yarn-debug.log*
16 | yarn-error.log*
17 |
18 | # Editor directories and files
19 | .idea
20 | .vscode
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - stable
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Release Notes
2 |
3 | ## [v0.6.0 (2020-10-04)]
4 |
5 |
6 | ### Changed
7 | - Updated the slot-scope name for tableData to tableFilters. the slot-scope for tableData now reflects the table data
8 |
9 |
10 | ## [v0.3.0 (2019-07-23)]
11 |
12 |
13 | ### Changed
14 | - Updated the event system to allow for different events to be passed through. Changed column prop `click-event` to `event` and `handler` ([#2f28d66](https://github.com/jamesdordoy/vue-datatable/commit/2f28d6646b4ed3c980d79d81f7c131c106a1aecd))
15 |
16 |
17 | ## [v0.3.1 (2019-08-12)]
18 |
19 |
20 | ### Changed
21 | - Added new column attribute `meta`. This allows custom values, functions etc. to be parsed to the custom components ([#2570f00](https://github.com/jamesdordoy/vue-datatable/commit/2570f0004f17cb1d1f220f956c90be4b7f6217c3))
22 |
23 | ## [v0.4.0 (2019-11-21)]
24 |
25 |
26 | ### Changed
27 | - Changed the model trait method in the Laravel Package. Changed method name `dataTableQuery` to `eloquentQuery` as there is now an additional method for using the Laravel Query Builder. ([#2570f00](https://github.com/jamesdordoy/vue-datatable/commit/2570f0004f17cb1d1f220f956c90be4b7f6217c3))
28 |
29 | ## [v0.5.0 (2019-12-26)]
30 |
31 |
32 | ### Changed
33 | - Changed the filterable column prop in the table to orderable as it is a more appropriate name. ([#a521a8](https://github.com/jamesdordoy/vue-datatable/commit/a521a86a4c17dba809a9d26c3d845f5c5b1cae31))
34 |
35 | ## [v0.6.0 (2020-01-23)]
36 |
37 | ### Changed
38 | - Changed table cell comp prop to component. ([#a521a8](https://github.com/jamesdordoy/vue-datatable/commit/a521a86a4c17dba809a9d26c3d845f5c5b1cae31))
39 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 James Dordoy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/jamesdordoy/Laravel-Vue-Datatable) [](https://www.npmjs.com/package/laravel-vue-datatable) [](https://www.npmjs.com/package/laravel-vue-datatable)
2 |
3 | # Laravel Vue Datatable
4 | A Vue.js datatable component for Laravel that works with Bootstrap & Tailwind by default.
5 |
6 | ## Requirements
7 |
8 | * [Vue.js](https://vuejs.org/) 2.x
9 | * [Laravel](http://laravel.com/docs/) 5.x
10 | * [Bootstrap](http://getbootstrap.com/) 4 (Optional)
11 | * [Tailwind](https://tailwindcss.com/) 1.* (Optional)
12 |
13 | ## Demo & Docs
14 |
15 | See [https://jamesdordoy.github.io/laravel-vue-datatable/](https://jamesdordoy.github.io/laravel-vue-datatable/)
16 |
17 | ## Example
18 | 
19 |
20 | ## Laravel Package Installation
21 | See details [https://github.com/jamesdordoy/Laravel-Vue-Datatable_Laravel-Package](https://github.com/jamesdordoy/Laravel-Vue-Datatable_Laravel-Package)
22 |
23 | ## Component Installation
24 |
25 | ```bash
26 | npm install laravel-vue-datatable
27 |
28 | or
29 |
30 | yarn add laravel-vue-datatable
31 | ```
32 |
33 | ### Register the Plugin
34 |
35 | ```javascript
36 | import DataTable from 'laravel-vue-datatable';
37 |
38 | Vue.use(DataTable);
39 | ```
40 |
41 | ### Basic Example
42 | > UserDatatable.vue
43 |
44 |
45 | ```html
46 |
49 |
50 | ```
51 |
52 | ```javascript
53 | export default {
54 | data() {
55 | return {
56 | columns: [
57 | {
58 | label: 'ID',
59 | name: 'id',
60 | orderable: true,
61 | },
62 | {
63 | label: 'Name',
64 | name: 'name',
65 | orderable: true,
66 | },
67 | {
68 | label: 'Email',
69 | name: 'email',
70 | orderable: true,
71 | },
72 | ]
73 | }
74 | },
75 | }
76 | ```
77 |
78 | ### API
79 |
80 | #### Datatable Props
81 |
82 | | Name | Type | Default | Description
83 | | --- | --- | --- | --- |
84 | | `url ` | String | "/" | The JSON url |
85 | | `columns` | Array | [] | The table columns |
86 | | `order-by` | String | "id" | (optional) The default column to order your data by |
87 | | `order-dir` | String | "asc" | (optional) The default order by direction |
88 | | `per-page` | Array | ['10','25','50'] | (optional) Amount to be displayed |
89 | | `theme` | String | "light" | (optional) Must be dark or light |
90 | | `framework` | String | "bootstrap" | (optional) Must be bootstrap or tailwind |
91 | | `debounce-delay` | Number | 0 | (optional) Adds a debounce delay to the get request when searching |
92 | | `classes` | Object | See Below | (optional) Table classes |
93 | | `translate` | Object | { nextButton: 'Next', previousButton: 'Previous', placeholderSearch: 'Search Table'} | (optional) used to overwrite the default pagination button text and search input placeholder |
94 | | `pagination` | Object | {} | (optional) props for [tailable/pagination](https://github.com/tailable/pagination#pagination-props) |
95 | | `add-filters-to-url` | Boolean | false | (optional) Will adjust the current url to keep track of used filters and will also store them in local storage. |
96 | | `headers` | Object | {} | Additional headers to pass route e.g. bearer token |
97 |
98 | #### Default Table Classes
99 |
100 | ```json
101 | {
102 | "table-container": {
103 | "table-responsive": true,
104 | },
105 | "table": {
106 | "table": true,
107 | "table-striped": true,
108 | "table-dark": true,
109 | },
110 | "t-head": {
111 |
112 | },
113 | "t-body": {
114 |
115 | },
116 | "t-head-tr": {
117 |
118 | },
119 | "t-body-tr": {
120 |
121 | },
122 | "td": {
123 |
124 | },
125 | "th": {
126 |
127 | },
128 | }
129 | ```
130 |
131 | ### Column Props
132 | | Name | Type | Default | Description
133 | | --- | --- | --- | --- |
134 | | `label` | String | "" | The table column label to be displayed as the column heading |
135 | | `name` | String | "" | The table column header name. You can also access nested properties e.g. a query using a with relationship using the dot notation. |
136 | | `columnName` | String | "" | (optional) The backend column name if the provided data keys do not match with the backend database. It may also be required to prefix the column name with the table name e.g. users.name to avoid issues with Integrity constraint violation when joining tables |
137 | | `width` | Number | 0 | (optional) The table column width |
138 | | `orderable` | Boolean | false | (optional) Is the column orderable in the datatable |
139 | | `component` | Component | null | (optional) A dynamic component that can be injected |
140 | | `event` | String | "" | (optional) Event type to parse to the component e.g. click, focus etc. |
141 | | `handler` | Function | () => {} | (optional) Callback function to parse for the event handler |
142 | | `transform` | Function | () => {} | (optional) Callback function to parse to manipulate the result. e.g. add currency symbol |
143 | | `classes` | Object | {} | (optional) Component classes to parse |
144 | | `meta` | Object | {} | (optional) Additional values that are parsed to component |
145 |
146 |
147 | ## Reloading the table manually
148 |
149 | If updates have been made to your dataset and you need to reload the table, you can attach a [ref](https://vuejs.org/v2/api/#vm-refs) to the table. Once the Vue.JS reference is attached, you are able to access the underlining methods of the component including the getData method.
150 |
151 | Alternatively, if you have custom filters applied and you would prefered they are retained, any adjustment to the url the table uses as a prop will reload the table.
152 |
153 |
154 | ## Further Examples
155 |
156 | See [https://jamesdordoy.github.io/laravel-vue-datatable/](https://jamesdordoy.github.io/laravel-vue-datatable/) for more examples.
157 |
158 | ## Development
159 |
160 | To work on the package locally or to add to the documentation, run the following command:
161 |
162 | ```bash
163 | npm run serve
164 | ```
165 |
166 | To deploy documentation to GitHub under a PR. Please run the following after uncommenting the outputDir line in the vue.config.js file:
167 |
168 | ```bash
169 | npm run build-docs
170 | ```
171 |
172 | To run the tests:
173 |
174 | ```bash
175 | npm run test
176 | ```
--------------------------------------------------------------------------------
/__tests__/App.test.js:
--------------------------------------------------------------------------------
1 | //Imports
2 | import App from '../documentation/App'
3 | import { shallowMount } from '@vue/test-utils'
4 |
5 | describe('Laravel Vue Data Tables Demo', () => {
6 | test('can be mounted cleanly', () => {
7 | const wrapper = shallowMount(App);
8 | expect(wrapper.isVueInstance()).toBeTruthy();
9 | });
10 | });
--------------------------------------------------------------------------------
/__tests__/DataTable.test.js:
--------------------------------------------------------------------------------
1 | //Imports
2 | import { shallowMount } from '@vue/test-utils'
3 | import DataTable from '../src/components/DataTable'
4 |
5 | describe('Data Table', () => {
6 | test('can be mounted cleanly', () => {
7 | const wrapper = shallowMount(DataTable, {
8 | propsData: {
9 | columns: [
10 | {
11 | label: 'ID',
12 | name: 'id',
13 | orderable: true,
14 | width: 10,
15 | },
16 | {
17 | label: 'Name',
18 | name: 'name',
19 | orderable: true,
20 | width: 20,
21 | },
22 | ],
23 | url: '',
24 | }
25 | });
26 |
27 | expect(wrapper.isVueInstance()).toBeTruthy();
28 | });
29 | });
--------------------------------------------------------------------------------
/__tests__/DataTableCell.test.js:
--------------------------------------------------------------------------------
1 | //Imports
2 | import { shallowMount } from '@vue/test-utils'
3 | import DataTableCell from '../src/components/DataTableCell'
4 |
5 | describe('Data Table Cell', () => {
6 | test('can be mounted cleanly', () => {
7 | const wrapper = shallowMount(DataTableCell, {
8 | propsData: {
9 | value:{
10 | name: 'test',
11 | },
12 | name: 'name'
13 | }
14 | });
15 |
16 | expect(wrapper.isVueInstance()).toBeTruthy();
17 | });
18 |
19 | test('can be mounted with correct prop values', () => {
20 | const wrapper = shallowMount(DataTableCell, {
21 | propsData: {
22 | value:{
23 | name: 'test',
24 | },
25 | name: 'name'
26 | }
27 | });
28 |
29 | expect(wrapper.props().value.name).toBe('test');
30 | expect(wrapper.props().name).toBe('name');
31 | });
32 |
33 | test('can be mounted with a default value', () => {
34 | const wrapper = shallowMount(DataTableCell, {
35 | propsData: {
36 | value:{
37 | name: 'test',
38 | },
39 | name: 'name'
40 | }
41 | });
42 |
43 | expect(wrapper.text()).toBe('test');
44 | });
45 |
46 | test('can tranform values', () => {
47 | const wrapper = shallowMount(DataTableCell, {
48 | propsData: {
49 | value:{
50 | name: 'james',
51 | },
52 | name: 'name',
53 | transform: ({data, name}) => { return data[name].charAt(0).toUpperCase() + data[name].slice(1) }
54 | }
55 | });
56 |
57 | expect(wrapper.text()).toBe('James');
58 | });
59 | });
--------------------------------------------------------------------------------
/__tests__/DataTableFilters.test.js:
--------------------------------------------------------------------------------
1 | //Imports
2 | import { shallowMount } from '@vue/test-utils'
3 | import DataTableFilters from '../src/components/DataTableFilters'
4 |
5 | describe('Data Table Filters', () => {
6 | test('can be mounted cleanly', () => {
7 | const wrapper = shallowMount(DataTableFilters, {
8 | propsData: {
9 | tableData: {
10 | filters: {},
11 | },
12 | perPage: [],
13 | },
14 | });
15 |
16 | expect(wrapper.isVueInstance()).toBeTruthy();
17 | });
18 | });
--------------------------------------------------------------------------------
/__tests__/DataTableHeader.test.js:
--------------------------------------------------------------------------------
1 | //Imports
2 | import { shallowMount } from '@vue/test-utils'
3 | import DataTableTh from '../src/components/DataTableTh'
4 |
5 | describe('Data Table Header', () => {
6 | test('can be mounted cleanly', () => {
7 | const wrapper = shallowMount(DataTableTh, {
8 | propsData: {
9 | column: {
10 |
11 | },
12 | dir: 'thing',
13 | },
14 | });
15 |
16 | expect(wrapper.isVueInstance()).toBeTruthy();
17 | });
18 | });
--------------------------------------------------------------------------------
/__tests__/Table.test.js:
--------------------------------------------------------------------------------
1 | //Imports
2 | import Table from '../src/components/Table'
3 | import { shallowMount } from '@vue/test-utils'
4 |
5 |
6 | describe('Table', () => {
7 | test('can be mounted cleanly', () => {
8 | const wrapper = shallowMount(Table, {
9 | propsData: {
10 | columns: [],
11 | url: '',
12 | },
13 | });
14 |
15 | expect(wrapper.isVueInstance()).toBeTruthy();
16 | });
17 | });
--------------------------------------------------------------------------------
/__tests__/bootstrap.js:
--------------------------------------------------------------------------------
1 | // Attach Vue
2 | global.Vue = require('vue');
3 |
4 | import VueRouter from 'vue-router';
5 |
6 | //Attach an alert function to the window as JSDOM dosnt do this but our components makes use of the function
7 | //https://stackoverflow.com/questions/55088482/jest-not-implemented-window-alert
8 | window.alert = () => {};
9 |
10 | //Ignore log and error console messages as exceptions are classed under these.
11 | global.console = {
12 | log: jest.fn(),
13 | error: jest.fn(),
14 | warn: console.warn,
15 | info: console.info,
16 | debug: console.debug,
17 | };
18 |
19 | Vue.use(VueRouter);
20 |
21 | import { TailablePagination } from 'tailable-pagination';
22 |
23 | Vue.component('tailable-pagination', TailablePagination);
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ],
5 | sourceType: 'unambiguous'
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/docs/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Single Page Apps for GitHub Pages
6 |
7 |
8 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/docs/css/app.4397df0e.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css?family=Oxanium&display=swap);@import url(https://fonts.googleapis.com/css?family=Varela+Round&display=swap);.show-code-inline{position:absolute;bottom:8px;right:18px}.switch[data-v-3365f90a]{position:relative;display:inline-block;width:46px;height:20px;margin-bottom:0}.switch input[data-v-3365f90a]{opacity:0;width:0;height:0}.slider[data-v-3365f90a]{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;-webkit-transition:.4s;transition:.4s}.slider[data-v-3365f90a]:before{position:absolute;content:"";height:12px;width:12px;left:4px;bottom:4px;background-color:#fff;-webkit-transition:.4s;transition:.4s}input:checked+.slider[data-v-3365f90a]{background-color:#2196f3}input:focus+.slider[data-v-3365f90a]{-webkit-box-shadow:0 0 1px #2196f3;box-shadow:0 0 1px #2196f3}input:checked+.slider[data-v-3365f90a]:before{-webkit-transform:translateX(26px);transform:translateX(26px)}.slider.round[data-v-3365f90a]{border-radius:34px}.slider.round[data-v-3365f90a]:before{border-radius:50%}li[data-v-df9fa13e]{padding:4px;margin:0}ul[data-v-df9fa13e]{margin:0;padding:0}a[data-v-2ccc1c8d]:hover{color:#4dc0b5}a[data-v-2ccc1c8d]{color:#3490dc}.vs__search{padding:2px!important}
2 |
3 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}b,strong{font-weight:bolder}code{font-family:monospace,monospace;font-size:1em}img{border-style:none}button,input,select{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}[type=checkbox]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}[hidden],template{display:none}h2,h5,p,pre{margin:0}button{background-color:transparent;background-image:none}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}ul{list-style:none;margin:0;padding:0}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-color:#e2e8f0}*,:after,:before,img{border-style:solid}input::-webkit-input-placeholder{color:#a0aec0}input::-moz-placeholder{color:#a0aec0}input:-ms-input-placeholder{color:#a0aec0}input::-ms-input-placeholder{color:#a0aec0}input::placeholder{color:#a0aec0}[role=button],button{cursor:pointer}table{border-collapse:collapse}h2,h5{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,select{padding:0;line-height:inherit;color:inherit}code,pre{font-family:Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}img,svg{display:block;vertical-align:middle}img{max-width:100%;height:auto}.bg-gray-100{--bg-opacity:1;background-color:#f7fafc;background-color:rgba(247,250,252,var(--bg-opacity))}.bg-gray-400{--bg-opacity:1;background-color:#cbd5e0;background-color:rgba(203,213,224,var(--bg-opacity))}.bg-gray-500{--bg-opacity:1;background-color:#a0aec0;background-color:rgba(160,174,192,var(--bg-opacity))}.bg-red-200{--bg-opacity:1;background-color:#fed7d7;background-color:rgba(254,215,215,var(--bg-opacity))}.bg-green-200{--bg-opacity:1;background-color:#c6f6d5;background-color:rgba(198,246,213,var(--bg-opacity))}.bg-blue-800{--bg-opacity:1;background-color:#2c5282;background-color:rgba(44,82,130,var(--bg-opacity))}.hover\:bg-gray-300:hover{--bg-opacity:1;background-color:#e2e8f0;background-color:rgba(226,232,240,var(--bg-opacity))}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.border-r{border-right-width:1px}.cursor-pointer{cursor:pointer}.block{display:block}.inline-block{display:inline-block}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.table{display:table}.hidden{display:none}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-shrink-0{-ms-flex-negative:0;flex-shrink:0}.float-right{float:right}.font-semibold{font-weight:600}.h-6{height:1.5rem}.h-10{height:2.5rem}.h-full{height:100%}.h-screen{height:100vh}.text-xs{font-size:.75rem}.text-sm{font-size:.875rem}.text-lg{font-size:1.125rem}.m-0{margin:0}.mx-auto{margin-left:auto;margin-right:auto}.-mx-4{margin-left:-1rem;margin-right:-1rem}.mt-0{margin-top:0}.mb-2{margin-bottom:.5rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.min-h-full{min-height:100%}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.p-0{padding:0}.p-2{padding:.5rem}.p-3{padding:.75rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.px-4{padding-left:1rem;padding-right:1rem}.pl-2{padding-left:.5rem}.pr-3{padding-right:.75rem}.pl-6{padding-left:1.5rem}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.top-0{top:0}.shadow{-webkit-box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06);box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px 0 rgba(0,0,0,.06)}.fill-current{fill:currentColor}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-white{--text-opacity:1;color:#fff;color:rgba(255,255,255,var(--text-opacity))}.text-gray-500{--text-opacity:1;color:#a0aec0;color:rgba(160,174,192,var(--text-opacity))}.text-gray-600{--text-opacity:1;color:#718096;color:rgba(113,128,150,var(--text-opacity))}.text-gray-800{--text-opacity:1;color:#2d3748;color:rgba(45,55,72,var(--text-opacity))}.text-gray-900{--text-opacity:1;color:#1a202c;color:rgba(26,32,44,var(--text-opacity))}.text-teal-800{--text-opacity:1;color:#285e61;color:rgba(40,94,97,var(--text-opacity))}.hover\:text-gray-700:hover{--text-opacity:1;color:#4a5568;color:rgba(74,85,104,var(--text-opacity))}.uppercase{text-transform:uppercase}.tracking-wide{letter-spacing:.025em}.whitespace-no-wrap{white-space:nowrap}.w-6{width:1.5rem}.w-10{width:2.5rem}.w-1\/3{width:33.333333%}.w-2\/3{width:66.666667%}.w-full{width:100%}.z-10{z-index:10}.transform{--transform-translate-x:0;--transform-translate-y:0;--transform-rotate:0;--transform-skew-x:0;--transform-skew-y:0;--transform-scale-x:1;--transform-scale-y:1;-webkit-transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y));transform:translateX(var(--transform-translate-x)) translateY(var(--transform-translate-y)) rotate(var(--transform-rotate)) skewX(var(--transform-skew-x)) skewY(var(--transform-skew-y)) scaleX(var(--transform-scale-x)) scaleY(var(--transform-scale-y))}.transition{-webkit-transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,-webkit-box-shadow,-webkit-transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,-webkit-box-shadow,-webkit-transform}@-webkit-keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes ping{75%,to{-webkit-transform:scale(2);transform:scale(2);opacity:0}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{-webkit-transform:translateY(-25%);transform:translateY(-25%);-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{-webkit-transform:none;transform:none;-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1)}}h2{font-size:1.875rem;margin-top:.5rem;margin-bottom:.5rem}.varela{font-family:Varela Round,sans-serif}.oxanium{font-family:Oxanium,cursive}body{padding-top:50px}.router-link-active{background:#cbd5e0!important;border:1px solid #ccc}.slideDown{-webkit-animation-name:slideDownAnimation;animation-name:slideDownAnimation;-webkit-animation-duration:1s;animation-duration:1s}.max-h-0{max-height:0}@-webkit-keyframes slideDownAnimation{0%{max-height:0%}to{max-height:auto}}@keyframes slideDownAnimation{0%{max-height:0%}to{max-height:auto}}.table{width:100%;max-width:100%;margin-bottom:1rem}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #eceeef}.table thead th{vertical-align:bottom;border-bottom:2px solid #eceeef}.table tbody+tbody{border-top:2px solid #eceeef}.table .table{background-color:#fff}@media (min-width:640px){.sm\:-mx-8{margin-left:-2rem;margin-right:-2rem}.sm\:px-8{padding-left:2rem;padding-right:2rem}}@media (min-width:768px){.md\:justify-start{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}}@media (min-width:1024px){.lg\:block{display:block}.lg\:hidden{display:none}.lg\:text-2xl{font-size:1.5rem}.lg\:w-1\/6{width:16.666667%}.lg\:w-5\/6{width:83.333333%}}
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 | Laravel Vue Datatable We're sorry but laravel-vue-datatable doesn't work properly without JavaScript enabled. Please enable it to continue.
--------------------------------------------------------------------------------
/documentation/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
25 |
26 |
38 |
--------------------------------------------------------------------------------
/documentation/assets/styles/main.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @import url('https://fonts.googleapis.com/css?family=Oxanium&display=swap');
6 | @import url('https://fonts.googleapis.com/css?family=Varela+Round&display=swap');
7 |
8 |
9 | h1 {
10 | @apply text-4xl my-2;
11 | }
12 |
13 | h2 {
14 | @apply text-3xl my-2;
15 | }
16 |
17 |
18 | h3 {
19 | @apply text-2xl my-2;
20 | }
21 |
22 | .varela {
23 | font-family: 'Varela Round', sans-serif;
24 | }
25 |
26 | .oxanium {
27 | font-family: 'Oxanium', cursive;
28 | }
29 |
30 | body {
31 | padding-top: 50px;
32 | }
33 |
34 | .router-link-active{
35 | background: #cbd5e0 !important;
36 | border: 1px solid #ccc;
37 | }
38 |
39 | .slideDown {
40 | animation-name: slideDownAnimation;
41 | animation-duration: 1s;
42 | }
43 |
44 | .max-h-0 {
45 | max-height: 0;
46 | }
47 |
48 | @keyframes slideDownAnimation {
49 | from { max-height: 0%; }
50 | to { max-height: auto; }
51 | }
52 |
53 |
54 |
55 | .table {
56 | width: 100%;
57 | max-width: 100%;
58 | margin-bottom: 1rem;
59 | }
60 |
61 | .table th,
62 | .table td {
63 | padding: 0.75rem;
64 | vertical-align: top;
65 | border-top: 1px solid #eceeef;
66 | }
67 |
68 | .table thead th {
69 | vertical-align: bottom;
70 | border-bottom: 2px solid #eceeef;
71 | }
72 |
73 | .table tbody + tbody {
74 | border-top: 2px solid #eceeef;
75 | }
76 |
77 | .table .table {
78 | background-color: #fff;
79 | }
80 |
81 | .table-sm th,
82 | .table-sm td {
83 | padding: 0.3rem;
84 | }
85 |
86 | .table-bordered {
87 | border: 1px solid #eceeef;
88 | }
89 |
90 | .table-bordered th,
91 | .table-bordered td {
92 | border: 1px solid #eceeef;
93 | }
94 |
95 | .table-bordered thead th,
96 | .table-bordered thead td {
97 | border-bottom-width: 2px;
98 | }
99 |
100 | .table-striped tbody tr:nth-of-type(odd) {
101 | background-color: rgba(0, 0, 0, 0.05);
102 | }
103 |
104 | .table-hover tbody tr:hover {
105 | background-color: rgba(0, 0, 0, 0.075);
106 | }
107 |
108 | .table-active,
109 | .table-active > th,
110 | .table-active > td {
111 | background-color: rgba(0, 0, 0, 0.075);
112 | }
113 |
114 | .table-hover .table-active:hover {
115 | background-color: rgba(0, 0, 0, 0.075);
116 | }
117 |
118 | .table-hover .table-active:hover > td,
119 | .table-hover .table-active:hover > th {
120 | background-color: rgba(0, 0, 0, 0.075);
121 | }
122 |
123 | .table-success,
124 | .table-success > th,
125 | .table-success > td {
126 | background-color: #dff0d8;
127 | }
128 |
129 | .table-hover .table-success:hover {
130 | background-color: #d0e9c6;
131 | }
132 |
133 | .table-hover .table-success:hover > td,
134 | .table-hover .table-success:hover > th {
135 | background-color: #d0e9c6;
136 | }
137 |
138 | .table-info,
139 | .table-info > th,
140 | .table-info > td {
141 | background-color: #d9edf7;
142 | }
143 |
144 | .table-hover .table-info:hover {
145 | background-color: #c4e3f3;
146 | }
147 |
148 | .table-hover .table-info:hover > td,
149 | .table-hover .table-info:hover > th {
150 | background-color: #c4e3f3;
151 | }
152 |
153 | .table-warning,
154 | .table-warning > th,
155 | .table-warning > td {
156 | background-color: #fcf8e3;
157 | }
158 |
159 | .table-hover .table-warning:hover {
160 | background-color: #faf2cc;
161 | }
162 |
163 | .table-hover .table-warning:hover > td,
164 | .table-hover .table-warning:hover > th {
165 | background-color: #faf2cc;
166 | }
167 |
168 | .table-danger,
169 | .table-danger > th,
170 | .table-danger > td {
171 | background-color: #f2dede;
172 | }
173 |
174 | .table-hover .table-danger:hover {
175 | background-color: #ebcccc;
176 | }
177 |
178 | .table-hover .table-danger:hover > td,
179 | .table-hover .table-danger:hover > th {
180 | background-color: #ebcccc;
181 | }
182 |
183 | .thead-inverse th {
184 | color: #fff;
185 | background-color: #292b2c;
186 | }
187 |
188 | .thead-default th {
189 | color: #464a4c;
190 | background-color: #eceeef;
191 | }
192 |
193 | .table-inverse {
194 | color: #fff;
195 | background-color: #292b2c;
196 | }
197 |
198 | .table-inverse th,
199 | .table-inverse td,
200 | .table-inverse thead th {
201 | border-color: #fff;
202 | }
203 |
204 | .table-inverse.table-bordered {
205 | border: 0;
206 | }
207 |
208 | .table-responsive {
209 | display: block;
210 | width: 100%;
211 | overflow-x: auto;
212 | -ms-overflow-style: -ms-autohiding-scrollbar;
213 | }
214 |
215 | .table-responsive.table-bordered {
216 | border: 0;
217 | }
218 |
219 | .table-dark {
220 | color: #fff;
221 | background-color: #343a40;
222 | }
--------------------------------------------------------------------------------
/documentation/components/Header.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 | Laravel Vue Datatable
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/documentation/example-components/DataTableAnchorCell.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ data[name] }}
3 |
4 |
5 |
15 |
16 |
--------------------------------------------------------------------------------
/documentation/example-components/DataTableButtonCell.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ name }}
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/documentation/example-components/DataTableCurrencyCell.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
${{ data[name] }}
4 |
USD
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/documentation/example-components/DataTableDateCell.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ data[name]|formatDate }}
3 |
4 |
5 |
15 |
16 |
--------------------------------------------------------------------------------
/documentation/example-components/DataTableDropdownCell.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/documentation/example-components/DataTableImageCell.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
--------------------------------------------------------------------------------
/documentation/example-components/DataTableIsActiveCell.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ data.is_active ? "Active" : "Inactive" }}
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/documentation/example-components/DataTableListCell.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/documentation/example-components/DataTableNameAndImageCell.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 | {{ data.name }}
13 |
14 |
{{ data.id|padDigit(6) }}
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/documentation/example-components/DataTableSelectCell.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ item.name }}
5 |
6 |
7 |
8 |
9 |
20 |
21 |
--------------------------------------------------------------------------------
/documentation/example-components/InformationAlert.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/documentation/example-components/Modal.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
This rows email address is: {{ row.email }}
13 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/documentation/example-components/ModalButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 | View Row {{ data.id }} Modal
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/documentation/example-components/Switch.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
30 |
31 |
--------------------------------------------------------------------------------
/documentation/filters/format-date.ts:
--------------------------------------------------------------------------------
1 | import moment from "moment";
2 |
3 | export default (value, format='Do MMMM YYYY') => {
4 | if (value) {
5 | return moment(String(value)).format(format);
6 | }
7 | return 'N/A';
8 | };
--------------------------------------------------------------------------------
/documentation/filters/pad-digit.ts:
--------------------------------------------------------------------------------
1 | export default (num, padlen, padchar) => {
2 | var pad_char = typeof padchar !== 'undefined' ? padchar : '0';
3 | var pad = new Array(1 + padlen).join(pad_char);
4 | return (pad + num).slice(-pad.length);
5 | }
--------------------------------------------------------------------------------
/documentation/main.ts:
--------------------------------------------------------------------------------
1 | //Imports
2 | import 'bootstrap';
3 | import Vue from 'vue';
4 | import Vuex from 'vuex';
5 | import App from './App.vue';
6 | import routes from './routes';
7 | import VueRouter from 'vue-router';
8 | import VueSweetalert2 from 'vue-sweetalert2';
9 | import 'sweetalert2/dist/sweetalert2.min.css';
10 | import createPersistedState from 'vuex-persistedstate';
11 | import { library } from '@fortawesome/fontawesome-svg-core';
12 | import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
13 |
14 | //Prism Code Highlighting
15 | import 'prismjs/components/prism-markup-templating.min.js';
16 | import 'prismjs/components/prism-php.min.js';
17 | import 'prismjs/components/prism-php-extras.min.js';
18 | import 'prismjs/components/prism-bash.min.js';
19 | import 'prismjs/components/prism-json.min.js';
20 |
21 | import "prismjs/themes/prism-okaidia.css";
22 | import "prismjs";
23 |
24 | //Import Styles (Tailwind)
25 | import 'bootstrap/dist/css/bootstrap.css';
26 |
27 | import './assets/styles/main.css';
28 |
29 | //Import Plugin
30 | import DataTable from '../src/plugin';
31 |
32 | Vue.use(VueSweetalert2);
33 |
34 | //Plugin Useage
35 | Vue.use(Vuex);
36 | Vue.use(DataTable);
37 | Vue.use(VueRouter);
38 |
39 | //Font Awesome
40 | import { faEye } from '@fortawesome/free-regular-svg-icons';
41 | import { faVuejs, faPhp, faLaravel, faGithub } from '@fortawesome/free-brands-svg-icons';
42 | import { faInfoCircle, faTable, faProjectDiagram, faRestroom, faHammer, faEllipsisV, faBars } from '@fortawesome/free-solid-svg-icons';
43 |
44 | library.add(
45 | faBars,
46 | faEllipsisV,
47 | faVuejs,
48 | faPhp,
49 | faGithub,
50 | faLaravel,
51 | faTable,
52 | faProjectDiagram,
53 | faInfoCircle,
54 | faEye,
55 | faRestroom,
56 | faHammer
57 | );
58 |
59 | Vue.component('font-awesome-icon', FontAwesomeIcon);
60 |
61 | import formatDateFilter from './filters/format-date';
62 | import padDigitFilter from './filters/pad-digit';
63 |
64 | //Filters
65 | Vue.filter('formatDate', formatDateFilter);
66 | Vue.filter('padDigit', padDigitFilter);
67 |
68 | //VueRouter
69 | const router = new VueRouter({
70 | mode: "history",
71 | base: "/",
72 | routes,
73 | scrollBehavior () {
74 | return { x: 0, y: 0 }
75 | },
76 | });
77 |
78 | //Turn off production tips
79 | Vue.config.productionTip = false;
80 |
81 | //VueX
82 | import state from './state';
83 | import mutations from './mutations';
84 |
85 | const store = new Vuex.Store({
86 | state,
87 | mutations,
88 | plugins: [createPersistedState()],
89 | });
90 |
91 | //App Instance
92 | new Vue({
93 | store,
94 | router,
95 | render: h => h(App),
96 | }).$mount('#app');
97 |
--------------------------------------------------------------------------------
/documentation/markdown/events/table.md:
--------------------------------------------------------------------------------
1 | ## Datatable Events
2 | | Name | Description
3 | | --- | --- |
4 | | loading | The table is loading new data |
5 | | finished-loading | The table has finished loading new data |
6 | | row-clicked | The table has had a row clicked |
7 | | on-table-props-changed | The table is about to reload due to a state change |
8 |
9 |
--------------------------------------------------------------------------------
/documentation/markdown/examples/basic.md:
--------------------------------------------------------------------------------
1 | ## HTML
2 |
3 | ```html
4 |
5 |
8 |
9 |
10 | ```
11 |
12 | ## Javascript
13 | ```javascript
14 | export default {
15 | data() {
16 | return {
17 | columns: [
18 | {
19 | label: 'ID',
20 | name: 'id',
21 | orderable: true,
22 | },
23 | {
24 | label: 'Name',
25 | name: 'name',
26 | orderable: true,
27 | },
28 | {
29 | label: 'Cost (£)',
30 | name: 'cost',
31 | orderable: true,
32 | transform: ({data, name}) => `£${data[name]}`,
33 | },
34 | {
35 | label: 'Email',
36 | name: 'email',
37 | orderable: true,
38 | },
39 | ]
40 | }
41 | },
42 | }
43 | ```
44 |
--------------------------------------------------------------------------------
/documentation/markdown/examples/crud.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesdordoy/laravel-vue-datatable/74551479adf10cfd702d6a6d03c10ac13f1e49e1/documentation/markdown/examples/crud.md
--------------------------------------------------------------------------------
/documentation/markdown/examples/custom-filters.md:
--------------------------------------------------------------------------------
1 | ### Datatable
2 |
3 | ```html
4 |
8 |
9 |
10 |
11 |
12 | {{ page }}
13 |
14 |
15 |
16 |
19 | All
20 | Active
21 | Inactive
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 | ```
35 |
36 | ```javascript
37 | data() {
38 | return {
39 | url: "http://example.test",
40 | columns: [
41 | ...
42 | ],
43 | filters: {
44 | isActive: '',
45 | },
46 | }
47 | },
48 | ```
49 |
50 | This added `isActive` filter will be send to the Laravel backend and can be used to manipulate the results:
51 |
52 | ```php
53 | $query = User::eloquentQuery(
54 | $request->input('column'),
55 | $request->input('dir'),
56 | $request->input('search')
57 | );
58 |
59 | $isActive = $request->input('isActive');
60 |
61 | if (isset($isActive)) {
62 | $query->where("is_active", $isActive);
63 | }
64 |
65 | $data = $query->paginate($request->input('length'));
66 |
67 | return new DataTableCollectionResource($data);
68 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/injecting-dynamic-components.md:
--------------------------------------------------------------------------------
1 | ### Example Button Component
2 |
3 | > (ExampleButton.vue)
4 |
5 | ```html
6 |
7 |
8 |
9 |
10 |
11 |
12 | {{ name }}
13 |
14 |
15 | ```
16 |
17 | ```javascript
18 | export default {
19 | props: {
20 | data: {},
21 | name: {},
22 | click: {
23 | type: Function,
24 | default: () => {}
25 | },
26 | classes: {
27 | type: Object,
28 | default: () => ({
29 | 'btn': true,
30 | 'btn-primary': true,
31 | 'btn-sm': true,
32 | }),
33 | },
34 | }
35 | }
36 | ```
37 |
38 | ### Example Image Component
39 |
40 | > (ExampleImageComponent.vue)
41 |
42 | ```html
43 |
44 |
45 |
46 | ```
47 |
48 | ```javascript
49 | export default {
50 | props: {
51 | data: {}
52 | }
53 | }
54 | ```
55 |
56 |
57 | ### Datatable Button Example
58 |
59 | > (UserDatatable.vue)
60 |
61 | ``` html
62 |
63 |
66 |
67 |
68 | ```
69 |
70 | ```javascript
71 | import ExampleButton './ExampleButton.vue';
72 | import ExampleImageComponent './ExampleImageComponent.vue';
73 |
74 | export default {
75 | data() {
76 | return {
77 | columns: [
78 | {
79 | label: 'ID',
80 | name: 'id',
81 | orderable: true,
82 | },
83 | {
84 | label: 'Name',
85 | name: 'name',
86 | orderable: true,
87 | },
88 | {
89 | label: 'Email',
90 | name: 'email',
91 | orderable: true,
92 | },
93 | {
94 | label: 'Profile Image',
95 | name: 'img',
96 | orderable: true,
97 | component: ExampleImageComponent,
98 | },
99 | {
100 | label: '',
101 | name: 'View',
102 | orderable: false,
103 | classes: {
104 | 'btn': true,
105 | 'btn-primary': true,
106 | 'btn-sm': true,
107 | },
108 | event: "click",
109 | handler: this.displayRow,
110 | component: ExampleButton,
111 | },
112 | ]
113 | }
114 | },
115 | components: {
116 | // eslint-disable-next-line
117 | ExampleButton,
118 | },
119 | methods: {
120 | displayRow(data) {
121 | alert(`You clicked row ${data.id}`);
122 | },
123 | },
124 | }
125 | ```
126 |
--------------------------------------------------------------------------------
/documentation/markdown/examples/joins-js.md:
--------------------------------------------------------------------------------
1 | > Datatable.vue
2 | ```html
3 |
4 |
7 |
8 |
9 | ```
10 |
11 | ```javascript
12 | export default {
13 | data() {
14 | return {
15 | columns: [
16 | {
17 | label: 'ID',
18 | name: 'id',
19 | orderable: true,
20 | },
21 | {
22 | label: 'Department Name',
23 | name: 'department_name',
24 | columnName: 'departments.name',
25 | orderable: true,
26 | },
27 | {
28 | label: 'Role Name',
29 | name: 'role_name',
30 | columnName: 'roles.name',
31 | orderable: true,
32 | },
33 | {
34 | label: 'Name',
35 | name: 'user_name',
36 | columnName: 'users.name',
37 | orderable: true,
38 | },
39 |
40 | {
41 | label: 'Email',
42 | name: 'email',
43 | orderable: true,
44 | },
45 | ]
46 | }
47 | },
48 | }
49 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/joins-php.md:
--------------------------------------------------------------------------------
1 | ```php
2 | input('search');
16 | $orderBy = $request->input('column');
17 | $orderBydir = $request->input("dir");
18 | $length = $request->input('length');
19 |
20 | $data = DB::table('users')
21 | ->join('roles', 'roles.id', '=', 'users.role_id')
22 | ->join('departments', 'departments.id', '=', 'roles.department_id')
23 | ->select(
24 | 'roles.name as role_name',
25 | 'users.id',
26 | 'users.cost',
27 | 'users.name as user_name',
28 | 'users.email',
29 | 'departments.name as department_name'
30 | )
31 | ->where("users.name", "LIKE", "%$searchValue%")
32 | ->orWhere('users.email', "LIKE", "%$searchValue%")
33 | ->orWhere('roles.name', "LIKE", "%$searchValue%")
34 | ->orWhere('departments.name', "LIKE", "%$searchValue%")
35 | ->orderBy($orderBy, $orderBydir)
36 | ->paginate($length);
37 |
38 | return new DataTableCollectionResource($data);
39 | }
40 | }
41 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/loading-animations.md:
--------------------------------------------------------------------------------
1 | ```html
2 |
3 |
4 |
10 |
11 |
14 |
15 |
16 |
17 | ```
18 |
19 | ```javascript
20 | // Import component
21 | import Loading from 'vue-loading-overlay';
22 | // Import stylesheet
23 | import 'vue-loading-overlay/dist/vue-loading.css';
24 |
25 | export default {
26 | data() {
27 | return {
28 | isLoading: false,
29 | columns: [
30 | {
31 | label: 'ID',
32 | name: 'id',
33 | orderable: true,
34 | },
35 | {
36 | label: 'Name',
37 | name: 'name',
38 | orderable: true,
39 | },
40 | {
41 | label: 'Email',
42 | name: 'email',
43 | orderable: true,
44 | },
45 | ]
46 | }
47 | },
48 | }
49 | ```
50 |
--------------------------------------------------------------------------------
/documentation/markdown/examples/modal.md:
--------------------------------------------------------------------------------
1 | > Modal.vue
2 | ``` html
3 |
4 |
5 |
6 |
7 |
13 |
14 |
This rows email address is: {{ row.email }}
15 |
16 |
19 |
20 |
21 |
22 |
23 | ```
24 |
25 | ``` javascript
26 | export default {
27 | props: {
28 | row: {
29 | type: Object,
30 | default: () => ({}),
31 | }
32 | }
33 | }
34 | ```
35 |
36 |
37 | > ModalButton.vue
38 | ```html
39 |
40 |
46 | View Row {{ data.id }} Modal
47 |
48 |
49 | ```
50 |
51 | ``` javascript
52 |
63 | ```
64 |
65 |
66 | > Datatable.vue
67 | ```html
68 |
69 |
72 |
73 |
75 |
76 |
77 | ```
78 |
79 | ```javascript
80 |
81 | import Modal from './MyModal';
82 | import ModalButton from './MyModalButton';
83 |
84 | export default {
85 | components: {
86 | Modal,
87 | ModalButton,
88 | },
89 | data() {
90 | return {
91 | columns: [
92 | {
93 | label: 'ID',
94 | name: 'id',
95 | orderable: true,
96 | },
97 | {
98 | label: 'Name',
99 | name: 'name',
100 | orderable: true,
101 | },
102 | {
103 | label: 'Email',
104 | name: 'email',
105 | orderable: true,
106 | },
107 | {
108 | label: 'View',
109 | name: '',
110 | orderable: false,
111 | component: ModalButton,
112 | event: "click",
113 | handler: this.updateSelectedModal,
114 | },
115 | ],
116 | selectedRow: {},
117 | }
118 | },
119 | methods: {
120 | updateSelectedModal(data) {
121 | this.selectedRow = data;
122 | }
123 | }
124 | }
125 | ```
126 |
--------------------------------------------------------------------------------
/documentation/markdown/examples/override-filters-and-pagination.md:
--------------------------------------------------------------------------------
1 | ### Pagination Changed On Datatable
2 |
3 | ```html
4 |
7 |
8 |
9 |
10 |
11 | Showing {{meta.from}} to {{meta.to}} of {{ meta.total }} Entries
12 |
13 |
14 |
15 |
19 | Prev
20 |
21 |
25 | Next
26 |
27 |
28 |
29 |
30 |
31 | ```
32 |
33 | Once the URL has been updated by your customer paginator or filters, the table will re-render. Alternatively, if updating the URL is troublesome, different table filters can be manipulated by your filters using the v-model directive:
34 |
35 | ### Filter Changed On Datatable
36 |
37 | > (DatatableFilter.vue)
38 |
39 | This example filter will control the length of the table manipulating the tableData.length property using v-model and will make use of a custom [select component](https://github.com/sagalbot/vue-select) to make use of predictive results.
40 |
41 | ```html
42 |
45 |
46 |
47 |
48 |
49 | {{ page }}
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 | ```
65 |
66 | ```javascript
67 | import vSelect from 'vue-select';
68 | import 'vue-select/dist/vue-select.css';
69 |
70 | export default {
71 | data() {
72 | return {
73 | url: "http://example.com/users",
74 | selectOptions: [],
75 | }
76 | },
77 | components: {
78 | vSelect,
79 | },
80 | created() {
81 | this.searchUsersByName();
82 | },
83 | methods: {
84 | updateSelectedUser(row, tableData) {
85 | if (row) {
86 | tableData.search = row.name;
87 | } else {
88 | tableData.search = '';
89 | }
90 | },
91 | searchUsersByName(term = '') {
92 | axios.get(this.url + term)
93 | .then(response => {
94 | this.selectOptions = response.data;
95 | });
96 | }
97 | }
98 | }
99 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/override-table-body.md:
--------------------------------------------------------------------------------
1 | ```html
2 |
3 |
6 |
7 |
11 |
14 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | ```
27 |
28 | ```js
29 | export default {
30 | data() {
31 | return {
32 | columns: [
33 | {
34 | label: 'ID',
35 | name: 'id',
36 | orderable: true,
37 | },
38 | {
39 | label: 'Name',
40 | name: 'name',
41 | orderable: true,
42 | },
43 | {
44 | label: 'Email',
45 | name: 'email',
46 | orderable: true,
47 | },
48 | ]
49 | }
50 | },
51 | methods: {
52 | showRowNumber(id) {
53 | alert(`you clicked row ${id}`);
54 | }
55 | }
56 | }
57 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/override-table-header.md:
--------------------------------------------------------------------------------
1 | ```html
2 |
3 |
6 |
7 |
8 | List
9 |
10 |
11 | ID
12 | Name
13 | Email
14 |
15 |
16 |
17 |
18 | ```
19 |
20 | ```js
21 | export default {
22 | data() {
23 | return {
24 | sortOrders: {},
25 | columns: [
26 | {
27 | label: 'ID',
28 | name: 'id',
29 | orderable: true,
30 | },
31 | {
32 | label: 'Name',
33 | name: 'name',
34 | orderable: true,
35 | },
36 | {
37 | label: 'Email',
38 | name: 'email',
39 | orderable: true,
40 | },
41 | ]
42 | }
43 | },
44 | mounted() {
45 | this.columns.forEach((column) => {
46 | this.sortOrders[column.name] = -1;
47 | });
48 | },
49 | methods: {
50 | sort(key, tableProps) {
51 | tableProps.column = key;
52 | this.sortOrders[key] = this.sortOrders[key] * -1;
53 | tableProps.dir = this.sortOrders[key] === 1 ? 'desc' : 'asc';
54 | }
55 | }
56 | }
57 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/own-data.md:
--------------------------------------------------------------------------------
1 | ```html
2 |
3 |
7 |
8 |
9 | ```
10 |
11 | ```javascript
12 | export default {
13 | data() {
14 | return {
15 | url: "http://example.test",
16 | data: {},
17 | tableProps: {
18 | search: '',
19 | length: 10,
20 | column: 'id',
21 | dir: 'asc'
22 | },
23 | columns: [
24 | {
25 | label: 'ID',
26 | name: 'id',
27 | orderable: true,
28 | },
29 | {
30 | label: 'Name',
31 | name: 'name',
32 | orderable: true,
33 | },
34 | {
35 | label: 'Email',
36 | name: 'email',
37 | orderable: true,
38 | },
39 | ]
40 | }
41 | },
42 | created() {
43 | this.getData(this.url);
44 | },
45 | methods: {
46 | getData(url = this.url, options = this.tableProps) {
47 | axios.get(url, {
48 | params: options
49 | })
50 | .then(response => {
51 | this.data = response.data;
52 | })
53 | // eslint-disable-next-line
54 | .catch(errors => {
55 | //Handle Errors
56 | })
57 | },
58 | reloadTable(tableProps) {
59 | this.getData(this.url, tableProps);
60 | }
61 | }
62 | }
63 | ```
64 |
--------------------------------------------------------------------------------
/documentation/markdown/examples/relationships/belongs-to-js.md:
--------------------------------------------------------------------------------
1 | #### JS
2 |
3 | > Datatable.vue
4 |
5 | ```js
6 | export default {
7 | data() {
8 | return {
9 | columns: [
10 | {
11 | label: 'ID',
12 | name: 'id',
13 | columnName: 'users.id',
14 | orderable: true,
15 | },
16 | {
17 | label: 'Name',
18 | name: 'name',
19 | columnName: 'users.name',
20 | orderable: true,
21 | },
22 | {
23 | label: 'Email',
24 | name: 'email',
25 | columnName: 'users.email',
26 | orderable: true,
27 | },
28 | {
29 | label: 'Role',
30 | name: 'role.name',
31 | columnName: 'roles.name',
32 | orderable: true,
33 | },
34 | ]
35 | }
36 | },
37 | }
38 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/relationships/belongs-to-many-js.md:
--------------------------------------------------------------------------------
1 | #### JS
2 |
3 | > ExampleSelectCell.vue
4 |
5 | ```html
6 |
7 |
12 |
13 | ```
14 |
15 | ```js
16 | export default {
17 | props: {
18 | data: {},
19 | name: {}
20 | },
21 | }
22 | ```
23 |
24 | > Datatable.vue
25 |
26 | ```js
27 | import ExampleSelectCell from './ExampleSelectCell';
28 |
29 | export default {
30 | data() {
31 | return {
32 | columns: [
33 | {
34 | label: 'ID',
35 | name: 'id',
36 | columnName: 'users.id',
37 | orderable: true,
38 | },
39 | {
40 | label: 'Name',
41 | name: 'name',
42 | columnName: 'users.name',
43 | orderable: true,
44 | },
45 | {
46 | label: 'Email',
47 | name: 'email',
48 | columnName: 'users.email',
49 | orderable: true,
50 | },
51 | {
52 | label: 'Departments',
53 | name: 'departments',
54 | columnName: 'departments.name',
55 | component: ExampleSelectCell,
56 | orderable: true,
57 | },
58 | ]
59 | }
60 | },
61 | }
62 |
63 | ```
64 |
--------------------------------------------------------------------------------
/documentation/markdown/examples/relationships/belongs-to-many-php.md:
--------------------------------------------------------------------------------
1 | #### PHP
2 |
3 | > Add the relationship to your model
4 |
5 | ```php
6 | [
10 | "departments" => [
11 | "model" => \App\Department::class,
12 | "foreign_key" => "role_id",
13 | "pivot" => [
14 | "table_name" => "department_user",
15 | "primary_key" => "id",
16 | "foreign_key" => "department_id",
17 | "local_key" => "user_id",
18 | ],
19 | "order_by" => "name",
20 | "columns" => [
21 | "name" => [
22 | "searchable" => true,
23 | "orderable" => true,
24 | ]
25 | ],
26 | ],
27 | ]
28 | ];
29 |
30 | public function departments()
31 | {
32 | return $this->belongsToMany(\App\Department::class, 'department_user', 'user_id', 'department_id');
33 | }
34 | ```
35 |
36 | > Attach the relationship to the query
37 |
38 | ```php
39 | input('column'),
51 | $request->input('dir'),
52 | $request->input('search'),
53 | [
54 | "departments"
55 | ]
56 | );
57 |
58 | $data = $query->paginate($request->input('length'));
59 |
60 | return new DataTableCollectionResource($data);
61 | }
62 | }
63 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/relationships/belongs-to-php.md:
--------------------------------------------------------------------------------
1 | #### PHP
2 |
3 | > Add the relationship to your model
4 |
5 | ```php
6 | [
10 | 'role' => [
11 | "model" => \App\Role::class,
12 | 'foreign_key' => 'role_id',
13 | 'columns' => [
14 | 'name' => [
15 | 'searchable' => true,
16 | 'orderable' => true,
17 | ],
18 | ],
19 | ],
20 | ],
21 | ];
22 |
23 | public function role()
24 | {
25 | return $this->belongsTo(\App\Role::class);
26 | }
27 | ```
28 |
29 | > Attach the relationship to the query
30 |
31 | ```php
32 | input('column'),
44 | $request->input('dir'),
45 | $request->input('search'),
46 | [
47 | "role",
48 | ]
49 | );
50 |
51 | $data = $query->paginate($request->input('length'));
52 |
53 | return new DataTableCollectionResource($data);
54 | }
55 | }
56 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/relationships/has-many-js.md:
--------------------------------------------------------------------------------
1 | #### JS
2 |
3 | > ExampleSelectCell.vue
4 |
5 | ```html
6 |
7 |
12 |
13 | ```
14 |
15 | ```js
16 | export default {
17 | props: {
18 | data: {},
19 | name: {}
20 | },
21 | }
22 | ```
23 |
24 | > Datatable.vue
25 |
26 | ```js
27 | import ExampleSelectCell from './ExampleSelectCell';
28 |
29 | export default {
30 | data() {
31 | return {
32 | columns: [
33 | {
34 | label: 'ID',
35 | name: 'id',
36 | columnName: 'users.id',
37 | orderable: true,
38 | },
39 | {
40 | label: 'Name',
41 | name: 'name',
42 | columnName: 'users.name',
43 | orderable: true,
44 | },
45 | {
46 | label: 'Email',
47 | name: 'email',
48 | columnName: 'users.email',
49 | orderable: true,
50 | },
51 | {
52 | label: 'Telephone Numbers',
53 | name: 'telephone_numbers',
54 | columnName: 'telephone_numbers.name',
55 | component: ExampleSelectCell,
56 | orderable: true,
57 | },
58 | ]
59 | }
60 | },
61 | }
62 |
63 | ```
64 |
--------------------------------------------------------------------------------
/documentation/markdown/examples/relationships/has-many-php.md:
--------------------------------------------------------------------------------
1 | #### PHP
2 |
3 | > Add the relationship to your model
4 |
5 | ```php
6 | [
10 | 'telephoneNumbers' => [
11 | "model" => \App\TelephoneNumber::class,
12 | 'foreign_key' => 'user_id',
13 | 'columns' => [
14 | 'name' => [
15 | 'searchable' => true,
16 | 'orderable' => true,
17 | ],
18 | ],
19 | ],
20 | ],
21 | ];
22 |
23 | public function telephoneNumbers()
24 | {
25 | return $this->hasMany(\App\TelephoneNumber::class);
26 | }
27 | ```
28 |
29 | > Attach the relationship to the query
30 |
31 | ```php
32 | input('column'),
44 | $request->input('dir'),
45 | $request->input('search'),
46 | [
47 | "telephoneNumbers",
48 | ]
49 | );
50 |
51 | $data = $query->paginate($request->input('length'));
52 |
53 | return new DataTableCollectionResource($data);
54 | }
55 | }
56 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/relationships/introduction.md:
--------------------------------------------------------------------------------
1 | > Add relationships to model
2 |
3 | ```php
4 | [
19 | 'searchable' => true,
20 | 'orderable' => true,
21 | ],
22 | 'name' => [
23 | 'searchable' => true,
24 | 'orderable' => true,
25 | ],
26 | 'email' => [
27 | 'searchable' => true,
28 | 'orderable' => true,
29 | ],
30 | ];
31 |
32 | protected $dataTableRelationships = [
33 | "belongsTo" => [
34 | ...
35 | ],
36 | "hasMany" => [
37 | ...
38 | ],
39 | "belongsToMany" => [
40 | ...
41 | ]
42 | ];
43 | }
44 |
45 | ```
46 |
47 | > BelongsTo
48 |
49 | ```php
50 | [
54 | "role" => [
55 | "model" => \App\Role::class,
56 | "foreign_key" => "role_id",
57 | "columns" => [
58 | "name" => [
59 | "searchable" => true,
60 | "orderable" => true,
61 | ],
62 | ],
63 | ],
64 | ],
65 | ];
66 | ```
67 |
68 | > HasMany
69 |
70 | ```php
71 | [
75 | "telephoneNumbers" => [
76 | "model" => \App\TelephoneNumber::class,
77 | "foreign_key" => "user_id",
78 | "columns" => [
79 | "name" => [
80 | "searchable" => true,
81 | "orderable" => true,
82 | ],
83 | ],
84 | ],
85 | ],
86 | ];
87 | ```
88 |
89 | > BelongsToMany
90 |
91 | ```php
92 | [
96 | "departments" => [
97 | "model" => \App\Department::class,
98 | "foreign_key" => "role_id",
99 | "pivot" => [
100 | "table_name" => "department_user",
101 | "primary_key" => "id",
102 | "foreign_key" => "department_id",
103 | "local_key" => "user_id",
104 | ],
105 | "order_by" => "name",
106 | "columns" => [
107 | "name" => [
108 | "searchable" => true,
109 | "orderable" => true,
110 | ]
111 | ],
112 | ],
113 | ]
114 | ];
115 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/relationships/mysql-config.md:
--------------------------------------------------------------------------------
1 | > config/database.php - MySQL example
2 |
3 | ```php
4 | 'strict' => false,
5 |
6 | or add
7 |
8 | 'modes' => [
9 | 'STRICT_ALL_TABLES',
10 | 'ERROR_FOR_DIVISION_BY_ZERO',
11 | 'NO_ZERO_DATE',
12 | 'NO_ZERO_IN_DATE',
13 | 'NO_AUTO_CREATE_USER',
14 | ],
15 | ```
--------------------------------------------------------------------------------
/documentation/markdown/examples/reloading-the-table.md:
--------------------------------------------------------------------------------
1 | If updates have been made to your dataset and you need to reload the table, you can attach a [ref](https://vuejs.org/v2/api/#vm-refs) to the table. Once the Vue.JS reference is attached, you are able to access the underlining methods of the component including the table's getData method.
2 |
3 | Alternatively, if you have custom filters applied and you would prefered they are retained, any adjustment to the url the table uses as a prop will reload the table.
--------------------------------------------------------------------------------
/documentation/markdown/examples/styling.md:
--------------------------------------------------------------------------------
1 | ### Tailwind Config
2 |
3 | > (mixins/tailwind.js)
4 |
5 | Custom Class
6 |
7 | ```css
8 | .stripped-table:nth-child(even) {
9 | @apply bg-black;
10 | }
11 | ```
12 |
13 | ```javascript
14 | export default {
15 | data() {
16 | return {
17 | classes: {
18 | 'table-container': {
19 | 'justify-center': true,
20 | 'w-full': true,
21 | 'flex': true,
22 | 'rounded': true,
23 | 'mb-6': true,
24 | 'shadow-md': true,
25 | },
26 | table: {
27 | 'text-left': true,
28 | 'w-full': true,
29 | 'border-collapse': true,
30 | },
31 | 't-head': {
32 | 'text-grey-dark': true,
33 | 'bg-black': true,
34 | 'border-grey-light': true,
35 | 'py-4': true,
36 | 'px-6': true,
37 | },
38 | "t-body": {
39 | 'bg-grey-darkest': true,
40 |
41 | },
42 | "t-head-tr": {
43 |
44 | },
45 | "t-body-tr": {
46 | 'stripped-table': true,
47 | 'bg-grey-darkest': true,
48 | },
49 | "td": {
50 | 'py-4': true,
51 | 'px-6': true,
52 | 'border-b': true,
53 | 'border-grey-light': true,
54 | 'text-grey-light': true,
55 | },
56 | "th": {
57 | 'py-4': true,
58 | 'px-6': true,
59 | 'font-bold': true,
60 | 'uppercase': true,
61 | 'text-sm': true,
62 | 'text-grey-dark': true,
63 | 'border-b': true,
64 | 'border-grey-light': true,
65 | },
66 | }
67 | };
68 | },
69 | }
70 | ```
71 |
72 | ### Tailwind Datatable
73 |
74 | ```html
75 |
80 |
81 |
84 |
85 |
86 |
87 |
88 |
93 |
94 |
95 |
96 | ```
97 |
98 | ```javascript
99 |
100 | import TailwindDatatable from '../mixins/tailwind.js';
101 |
102 | export default {
103 | data() {
104 | return {
105 | url: 'http://vue-datatable.test/ajax',
106 | perPage: ['10', '25', '50'],
107 | columns: [
108 | {
109 | label: 'ID',
110 | name: 'id',
111 | orderable: true,
112 | },
113 | {
114 | label: 'Name',
115 | name: 'name',
116 | orderable: true,
117 | },
118 | {
119 | label: 'Email',
120 | name: 'email',
121 | orderable: true,
122 | }
123 | ]
124 | }
125 | },
126 | mixins: [
127 | TailwindDatatable
128 | ]
129 | }
130 | ```
131 |
--------------------------------------------------------------------------------
/documentation/markdown/install.md:
--------------------------------------------------------------------------------
1 | ## Component Installation
2 |
3 |
4 | ```bash
5 | npm install laravel-vue-datatable
6 | ```
7 |
8 | or
9 |
10 | ```bash
11 | yarn add laravel-vue-datatable
12 | ```
13 |
14 | ### Register the Plugin
15 |
16 | ```javascript
17 | import DataTable from 'laravel-vue-datatable';
18 |
19 | Vue.use(DataTable);
20 | ```
--------------------------------------------------------------------------------
/documentation/markdown/introduction.md:
--------------------------------------------------------------------------------
1 | # Laravel Vue Datatable
2 | A Vue.js datatable component for Laravel that works with Bootstrap & Tailwind.
3 |
4 | ## Requirements
5 |
6 | * [Vue.js](https://vuejs.org/) 2.x
7 | * [Laravel](http://laravel.com/docs/) 5.x +
8 | * [Bootstrap](http://getbootstrap.com/) 4 (Optional)
9 |
--------------------------------------------------------------------------------
/documentation/markdown/laravel/adding-trait.md:
--------------------------------------------------------------------------------
1 | ## Use the Trait
2 |
3 | This trait is optional and provides a methods for filtering your data based on the attributes set in the model. If you would like more control on how the data is filtered, feel free to omit this trait use your own filtering methods. Just remember to paginate the results for the API Resource!
4 |
5 |
6 | ```php
7 | [
22 | 'searchable' => false,
23 | ],
24 | 'name' => [
25 | 'searchable' => true,
26 | ],
27 | 'email' => [
28 | 'searchable' => true,
29 | ]
30 | ];
31 |
32 | protected $dataTableRelationships = [
33 | //
34 | ];
35 | }
36 | ```
--------------------------------------------------------------------------------
/documentation/markdown/laravel/controller-resource.md:
--------------------------------------------------------------------------------
1 | ## Use the Controller Resource
2 |
3 | The Collection Resource is expecting a paginated collection, so feel free to use your own queries and omit the provided trait query if your require more complex filtering.
4 |
5 | ```php
6 | input('length');
19 | $sortBy = $request->input('column');
20 | $orderBy = $request->input('dir');
21 | $searchValue = $request->input('search');
22 |
23 | $query = User::eloquentQuery($sortBy, $orderBy, $searchValue);
24 |
25 | $data = $query->paginate($length);
26 |
27 | return new DataTableCollectionResource($data);
28 | }
29 | }
30 | ```
--------------------------------------------------------------------------------
/documentation/markdown/laravel/install.md:
--------------------------------------------------------------------------------
1 | ## Package Installation
2 |
3 | ```bash
4 | composer require jamesdordoy/laravelvuedatatable
5 | ```
6 |
7 |
8 | ## Add Service Provider
9 | Add the following line to your \config\app.php
10 |
11 | ```php
12 | JamesDordoy\LaravelVueDatatable\Providers\LaravelVueDatatableServiceProvider::class,
13 | ```
14 |
15 |
16 | ## Publish the Config
17 | ```php
18 | php artisan vendor:publish --provider="JamesDordoy\LaravelVueDatatable\Providers\LaravelVueDatatableServiceProvider"
19 | ```
--------------------------------------------------------------------------------
/documentation/markdown/laravel/options.md:
--------------------------------------------------------------------------------
1 | ## Package Options
2 |
3 | ```php
4 | [
5 | 'models' => [
6 | "search_term" => "searchable",
7 | "order_term" => "orderable",
8 | ],
9 | "default_order_by" => "id",
10 | ];
11 | ```
--------------------------------------------------------------------------------
/documentation/markdown/props/cell.md:
--------------------------------------------------------------------------------
1 | ## Cell Props
2 | | Name | Type | Default | Description
3 | | --- | --- | --- | --- |
4 | | name | String | "" | The column name |
5 | | value | Object | {} | The table row |
6 | | meta | Object | {} | (optional) Additional values that are parsed to cell |
7 | | comp | Component | Vue.Component | (optional) A dynamic component that can be injected |
8 | | event | String | "" | (optional) Event type to parse to the component e.g. click, focus etc. |
9 | | handler | Function | () => {} | (optional) Function to parse for the event handler |
10 | | classes | Object | {} | (optional) Cell classes to parse |
--------------------------------------------------------------------------------
/documentation/markdown/props/column.md:
--------------------------------------------------------------------------------
1 | ## Column Props
2 | | Name | Type | Default | Description
3 | | --- | --- | --- | --- |
4 | | label | String | "" | The table column label to be displayed as the column heading |
5 | | name | String | "" | The table column header name. You can also access nested properties e.g. a query using a with relationship using the dot notation. |
6 | | columnName | String | "" | (optional) The backend column name if the provided data keys do not match with the backend database. It may also be required to prefix the column name with the table name e.g. users.name to avoid issues with Integrity constraint violation when joining tables |
7 | | width | Number | 0 | (optional) The table column width |
8 | | orderable | Boolean | false | (optional) Is the column orderable in the datatable |
9 | | component | Component | null | (optional) A dynamic component that can be injected |
10 | | event | String | "" | (optional) Event type to parse to the component e.g. click, focus etc. |
11 | | handler | Function | () => {} | (optional) Function to parse for the event handler |
12 | | classes | Object | {} | (optional) Component classes to parse |
13 | | meta | Object | {} | (optional) Additional values that are parsed to component |
--------------------------------------------------------------------------------
/documentation/markdown/props/table.md:
--------------------------------------------------------------------------------
1 | ## Datatable Props
2 | | Name | Type | Default | Description
3 | | --- | --- | --- | --- |
4 | | url | String | "/" | The JSON url |
5 | | columns | Array | [] | The table columns |
6 | | order-by | String | "id" | (optional) The default column to order your data by |
7 | | order-dir | String | "asc" | (optional) The default order by direction |
8 | | per-page | Array | ['10','25','50'] | (optional) Amount to be displayed |
9 | | theme | String | "light" | (optional) Must be dark or light |
10 | | translate | Object | { nextButton: 'Next', previousButton: 'Previous', placeholderSearch: 'Search Table'} | (optional) used to overwrite the default pagination button text and search input placeholder |
11 | | debounce-delay | Number | 0 | (optional) Adds a debounce delay to the get request when searching |
12 | | add-filters-to-url | Boolean | false | (optional) Will adjust the current url to keep track of used filters and will also store them in local storage.
|
13 | | classes | Object | See Below | (optional) Table classes |
14 | | pagination | Object | {} | (optional) props for [gilbitron/laravel-vue-pagination](https://github.com/gilbitron/laravel-vue-pagination#props) |
15 | | headers | Object | {} | Additional headers to pass route e.g. bearer token |
16 |
17 |
18 | ### Default Classes
19 | ```json
20 | {
21 | "table-container": {
22 | "table-responsive": true,
23 | },
24 | "table": {
25 | "table": true,
26 | "table-striped": true,
27 | "border": true,
28 | },
29 | "t-head": {
30 |
31 | },
32 | "t-body": {
33 |
34 | },
35 | "t-head-tr": {
36 |
37 | },
38 | "t-body-tr": {
39 |
40 | },
41 | "td": {
42 |
43 | },
44 | "th": {
45 |
46 | },
47 | }
48 | ```
49 |
--------------------------------------------------------------------------------
/documentation/mixins/CodeExample.js:
--------------------------------------------------------------------------------
1 | import { mapState } from 'vuex';
2 |
3 | export default {
4 | data() {
5 | return {
6 | code: this.$store.state.showCode,
7 | }
8 | },
9 | computed: mapState(['showCode']),
10 | watch: {
11 | showCode(newValue) {
12 | this.code = newValue;
13 | }
14 | },
15 | mounted() {
16 | let styleingFunction = element => {
17 | element.style.overflowWrap = "normal";
18 | element.style.whiteSpace = "normal";
19 | };
20 |
21 | let paragraphs = document.querySelectorAll("p");
22 | let h1 = document.querySelectorAll("h1");
23 | let h2 = document.querySelectorAll("h2");
24 | let h3 = document.querySelectorAll("h3");
25 | let h4 = document.querySelectorAll("h4");
26 | let h5 = document.querySelectorAll("h5");
27 |
28 | paragraphs.forEach(styleingFunction);
29 | h1.forEach(styleingFunction);
30 | h2.forEach(styleingFunction);
31 | h3.forEach(styleingFunction);
32 | h4.forEach(styleingFunction);
33 | h5.forEach(styleingFunction);
34 | }
35 | }
--------------------------------------------------------------------------------
/documentation/mixins/CorrectTableStyling.js:
--------------------------------------------------------------------------------
1 | export default {
2 | mounted() {
3 | document.querySelectorAll("table").forEach(table => {
4 | table.classList.add("table");
5 | table.classList.add("table-bordered");
6 | table.classList.add("table-striped");
7 | });
8 | }
9 | }
--------------------------------------------------------------------------------
/documentation/mixins/CorrectTextStyling.js:
--------------------------------------------------------------------------------
1 | export default {
2 | mounted() {
3 | let styleingFunction = element => {
4 | element.style.overflowWrap = "normal";
5 | element.style.whiteSpace = "normal";
6 | };
7 |
8 | let paragraphs = document.querySelectorAll("p");
9 | let h1 = document.querySelectorAll("h1");
10 | let td = document.querySelectorAll("td");
11 | let h2 = document.querySelectorAll("h2");
12 | let h3 = document.querySelectorAll("h3");
13 | let h4 = document.querySelectorAll("h4");
14 | let h5 = document.querySelectorAll("h5");
15 |
16 | paragraphs.forEach(styleingFunction);
17 | h1.forEach(styleingFunction);
18 | h2.forEach(styleingFunction);
19 | h3.forEach(styleingFunction);
20 | h4.forEach(styleingFunction);
21 | h5.forEach(styleingFunction);
22 |
23 | td.forEach(styleingFunction);
24 | }
25 | }
--------------------------------------------------------------------------------
/documentation/mutations.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | showCode (state) {
3 | state.showCode = true;
4 | },
5 | hideCode (state) {
6 | state.showCode = false;
7 | }
8 | };
--------------------------------------------------------------------------------
/documentation/routes.ts:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | path: '/laravel-vue-datatable',
4 | component: require('../documentation/views/Introduction.vue').default,
5 | },
6 | {
7 | path: '/laravel-vue-datatable/installation',
8 | component: require('../documentation/views/Install.vue').default,
9 | },
10 | {
11 | path: '/laravel-vue-datatable/props/table',
12 | component: require('../documentation/views/props/Table.vue').default,
13 | },
14 | {
15 | path: '/laravel-vue-datatable/props/column',
16 | component: require('../documentation/views/props/Column.vue').default,
17 | },
18 | {
19 | path: '/laravel-vue-datatable/props/cell',
20 | component: require('../documentation/views/props/Cell.vue').default,
21 | },
22 | {
23 | path: '/laravel-vue-datatable/events/table',
24 | component: require('../documentation/views/events/Table.vue').default,
25 | },
26 | {
27 | path: '/laravel-vue-datatable/laravel/installation',
28 | component: require('../documentation/views/laravel/Install.vue').default,
29 | },
30 | {
31 | path: '/laravel-vue-datatable/laravel/options',
32 | component: require('../documentation/views/laravel/Options.vue').default,
33 | },
34 | {
35 | path: '/laravel-vue-datatable/laravel/trait',
36 | component: require('../documentation/views/laravel/AddingTrait.vue').default,
37 | },
38 | {
39 | path: '/laravel-vue-datatable/laravel/controller-resource',
40 | component: require('../documentation/views/laravel/ControllerResource.vue').default,
41 | },
42 | {
43 | path: '/laravel-vue-datatable/examples/basic',
44 | component: require('../documentation/views/examples/Basic.vue').default,
45 | },
46 | {
47 | path: '/laravel-vue-datatable/examples/tailwind',
48 | component: require('../documentation/views/examples/Tailwind.vue').default,
49 | },
50 | {
51 | path: '/laravel-vue-datatable/examples/loading-animations',
52 | component: require('../documentation/views/examples/LoadingAnimations.vue').default,
53 | },
54 | {
55 | path: '/laravel-vue-datatable/examples/relationships',
56 | component: require('../documentation/views/examples/relationships/Introduction.vue').default,
57 | },
58 | {
59 | path: '/laravel-vue-datatable/examples/belongs-to',
60 | component: require('../documentation/views/examples/relationships/BelongsTo.vue').default,
61 | },
62 | {
63 | path: '/laravel-vue-datatable/examples/has-many',
64 | component: require('../documentation/views/examples/relationships/HasMany.vue').default,
65 | },
66 | {
67 | path: '/laravel-vue-datatable/examples/belongs-to-many',
68 | component: require('../documentation/views/examples/relationships/BelongsToMany.vue').default,
69 | },
70 | {
71 | path: '/laravel-vue-datatable/examples/injecting-dynamic-components',
72 | component: require('../documentation/views/examples/InjectingDynamicComponents.vue').default,
73 | },
74 | {
75 | path: '/laravel-vue-datatable/examples/override-filters',
76 | component: require('../documentation/views/examples/OverrideFiltersAndPagination.vue').default,
77 | },
78 | {
79 | path: '/laravel-vue-datatable/examples/override-table-body',
80 | component: require('../documentation/views/examples/OverrideTableBody.vue').default,
81 | },
82 | {
83 | path: '/laravel-vue-datatable/examples/override-table-header',
84 | component: require('../documentation/views/examples/OverrideTableHeader.vue').default,
85 | },
86 | {
87 | path: '/laravel-vue-datatable/examples/custom-filters',
88 | component: require('../documentation/views/examples/CustomFilters.vue').default,
89 | },
90 | {
91 | path: '/laravel-vue-datatable/examples/reload-table',
92 | component: require('../documentation/views/examples/ReloadingTheTable.vue').default,
93 | },
94 |
95 | {
96 | path: '/laravel-vue-datatable/examples/styling',
97 | component: require('../documentation/views/examples/Styling.vue').default,
98 | },
99 | {
100 | path: '/laravel-vue-datatable/examples/modal',
101 | component: require('../documentation/views/examples/Modal.vue').default,
102 | },
103 | {
104 | path: '/laravel-vue-datatable/examples/crud',
105 | component: require('../documentation/views/Soon.vue').default,
106 | },
107 | {
108 | path: '/laravel-vue-datatable/examples/own-data',
109 | component: require('../documentation/views/examples/UsingYourOwnData.vue').default,
110 | },
111 | {
112 | path: '/laravel-vue-datatable/examples/joins',
113 | component: require('../documentation/views/examples/Joins.vue').default,
114 | },
115 | ];
--------------------------------------------------------------------------------
/documentation/state.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | showCode: false
3 | };
--------------------------------------------------------------------------------
/documentation/views/Install.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
30 |
--------------------------------------------------------------------------------
/documentation/views/Introduction.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
24 |
--------------------------------------------------------------------------------
/documentation/views/Soon.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/documentation/views/events/Table.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
26 |
--------------------------------------------------------------------------------
/documentation/views/examples/Basic.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Basic Example
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
82 |
--------------------------------------------------------------------------------
/documentation/views/examples/CRUD.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
65 |
--------------------------------------------------------------------------------
/documentation/views/examples/CustomFilters.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 |
16 | You can also add your own custom filters to be sent to the Laravel backend
17 |
18 |
19 |
20 |
21 |
22 |
23 |
28 |
29 |
30 |
31 |
32 | {{ page }}
33 |
34 |
35 |
36 |
39 | All
40 | Active
41 | Inactive
42 |
43 |
44 |
45 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
132 |
--------------------------------------------------------------------------------
/documentation/views/examples/InjectingDynamicComponents.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 |
16 | You can also inject your own components into the table such as buttons. Your buttons, links etc can also listen for events. After declaring your event type and setting a handler. You can accept the event type as you would expect in your component, e.g. click
for click events.
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
109 |
--------------------------------------------------------------------------------
/documentation/views/examples/Joins.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | Show Example Code
12 |
13 |
14 |
15 |
16 |
17 |
18 | For more complex filtering, it is suggested to use the query builder as you are able to make cross table queries and searches in only a single call to the database.
19 | This will also provide you with the most control over how data is selected and searched upon.
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | You will also need to add an additional attribute to each column as columnName
to any column names that have been changed. This will be sent to the backend for filtering and searching. It is required you prefix these values with their table name where Integrity constraint violations may be present due to duplicated column names.
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
48 | {{ page }}
49 |
50 |
51 |
52 |
55 | All
56 | Active
57 | Inactive
58 |
59 |
60 |
61 |
64 | All
65 | User
66 | Staff
67 | Admin
68 |
69 |
70 |
71 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
154 |
--------------------------------------------------------------------------------
/documentation/views/examples/LoadingAnimations.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 | This example makes use of the vue-loading-overlay
Vue.js plugin which can be found here but you can use any loading animations you want.
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
84 |
--------------------------------------------------------------------------------
/documentation/views/examples/Modal.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
24 |
25 |
27 |
28 |
29 |
30 |
31 |
97 |
--------------------------------------------------------------------------------
/documentation/views/examples/OverrideFiltersAndPagination.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Show Example Code
11 |
12 |
13 |
14 |
15 |
16 |
17 | If the included pagination or filters do not meet your requirements or if the styling is incorrect, they can be overridden using scoped slots.
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 | {{ page }}
34 |
35 |
36 |
37 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | Showing {{ meta.from }} to {{ meta.to }} of {{ meta.total }} Entries
53 |
54 |
55 |
56 |
60 | Prev
61 |
62 |
66 | Next
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
80 |
81 |
146 |
--------------------------------------------------------------------------------
/documentation/views/examples/OverrideTableBody.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 |
16 | If you want more control over the rendered table rows, you can use the body
slot to override the default table HTML.
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
28 |
29 |
33 |
36 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
100 |
--------------------------------------------------------------------------------
/documentation/views/examples/OverrideTableHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 |
16 | Note you will need to manage column sorting using your own methods.
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
28 |
29 |
30 | List
31 |
32 |
33 | ID
34 | Name
35 | Email
36 |
37 |
38 |
39 |
40 |
41 |
42 |
102 |
--------------------------------------------------------------------------------
/documentation/views/examples/ReloadingTheTable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | Show Example Code
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Reload Table
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
88 |
--------------------------------------------------------------------------------
/documentation/views/examples/Styling.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 | You can edit the style of the Datatable by overriding the classes
prop. A example mixin config can be found be below for Tailwind:
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | You can attach classes to each table as required using the classes prop
19 |
20 |
21 |
22 |
23 |
65 |
--------------------------------------------------------------------------------
/documentation/views/examples/Tailwind.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 |
16 | To change to the provided Tailwind UI just add framework="tailwind" to your table
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
114 |
--------------------------------------------------------------------------------
/documentation/views/examples/UsingYourOwnData.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
27 |
28 |
29 |
99 |
--------------------------------------------------------------------------------
/documentation/views/examples/relationships/BelongsTo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 | Note that the Datatable columnName attributes reflect their table name as well. This is to avoid integrity contraint violations caused by ambiguoius column selection.
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
88 |
--------------------------------------------------------------------------------
/documentation/views/examples/relationships/BelongsToMany.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 | Note that the Datatable columnName attributes reflect their table name as well. This is to avoid integrity contraint violations caused by ambiguoius column selection.
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
91 |
--------------------------------------------------------------------------------
/documentation/views/examples/relationships/HasMany.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Show Example Code
10 |
11 |
12 |
13 |
14 |
15 | Note that the Datatable columnName attributes reflect their table name as well. This is to avoid integrity contraint violations caused by ambiguoius column selection.
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
90 |
--------------------------------------------------------------------------------
/documentation/views/examples/relationships/Introduction.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | The current implementation requires that you disable ONLY_FULL_GROUP_BY in your database configuration.
6 |
7 | Run php artisan config:cache
after making your changes to your database configuration.
8 |
9 | If you cannot turn off strict mode or are unable to remove the ONLY_FULL_GROUP_BY configuration. You can still make use of this packing using your own Eloquent or QueryBuilder queries and by paginating the results for the Datatable Collection Resource.
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
45 |
--------------------------------------------------------------------------------
/documentation/views/laravel/AddingTrait.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
25 |
--------------------------------------------------------------------------------
/documentation/views/laravel/ControllerResource.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
23 |
--------------------------------------------------------------------------------
/documentation/views/laravel/Install.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
23 |
--------------------------------------------------------------------------------
/documentation/views/laravel/Options.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
23 |
--------------------------------------------------------------------------------
/documentation/views/props/Cell.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
26 |
--------------------------------------------------------------------------------
/documentation/views/props/Column.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
26 |
--------------------------------------------------------------------------------
/documentation/views/props/Table.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
26 |
--------------------------------------------------------------------------------
/editor.conf:
--------------------------------------------------------------------------------
1 | # top-most EditorConfig file
2 | root = true
3 |
4 | # Unix-style newlines with a newline ending every file
5 | [*]
6 | end_of_line = lf
7 | insert_final_newline = true
8 |
9 | # Matches multiple files with brace expansion notation
10 | # Set default charset
11 | [*.{js,py}]
12 | charset = utf-8
13 |
14 | # 4 space indentation
15 | [*.js,*.vue ]
16 | indent_style = space
17 | indent_size = 4
18 |
19 | # Tab indentation (no size specified)
20 | [Makefile]
21 | indent_style = tab
22 |
23 | # Indentation override for all JS under lib directory
24 | [lib/**.js]
25 | indent_style = space
26 | indent_size = 4
27 |
28 | # Matches the exact files either package.json or .travis.yml
29 | [{package.json,.travis.yml}]
30 | indent_style = space
31 | indent_size = 2
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
3 | "setupFilesAfterEnv": [
4 | "/__tests__/bootstrap.js"
5 | ],
6 | "testPathIgnorePatterns": [
7 | "/__tests__/bootstrap.*"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "laravel-vue-datatable",
3 | "version": "0.6.0",
4 | "description": "Vue.js datatable made with Laravel and Bootstrap in mind",
5 | "author": "James Dordoy ",
6 | "homepage": "https://jamesdordoy.github.io/laravel-vue-datatable/",
7 | "private": false,
8 | "main": "./dist/laravel-vue-datatable.common.js",
9 | "keywords": [
10 | "vue",
11 | "component",
12 | "bootstrap",
13 | "tailwind.css",
14 | "laravel"
15 | ],
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/jamesdordoy/Laravel-Vue-Datatable.git"
19 | },
20 | "scripts": {
21 | "serve": "vue-cli-service serve documentation/main.ts",
22 | "build": "vue-cli-service build --target lib src/plugin.ts",
23 | "build-docs": "vue-cli-service build documentation/main.ts",
24 | "lint": "vue-cli-service lint",
25 | "test": "jest"
26 | },
27 | "dependencies": {
28 | "axios": "^0.27.2",
29 | "lodash.debounce": "^4.0.8",
30 | "lodash.defaultsdeep": "^4.6.1",
31 | "tailable-pagination": "^2.0.0",
32 | "vue": "^2.6.14"
33 | },
34 | "devDependencies": {
35 | "@fortawesome/fontawesome-svg-core": "^1.2.22",
36 | "@fortawesome/free-brands-svg-icons": "^5.10.2",
37 | "@fortawesome/free-regular-svg-icons": "^5.10.2",
38 | "@fortawesome/free-solid-svg-icons": "^5.10.2",
39 | "@fortawesome/vue-fontawesome": "^0.1.7",
40 | "@fullhuman/postcss-purgecss": "^4.1.3",
41 | "@types/jest": "27.5.1",
42 | "@vue/vue2-jest": "27.0.0",
43 | "@vue/cli-plugin-babel": "^5.0.4",
44 | "@vue/cli-plugin-typescript": "^5.0.4",
45 | "@vue/cli-plugin-unit-jest": "^5.0.4",
46 | "@vue/cli-service": "^5.0.4",
47 | "@vue/test-utils": "1.3.0",
48 | "babel-jest": "27.0.0",
49 | "bootstrap": "^5.1.3",
50 | "core-js": "^3.22.7",
51 | "jest": "27.0.0",
52 | "jest-localstorage-mock": "^2.4.21",
53 | "jest-serializer-vue": "^2.0.2",
54 | "jquery": "^3.6.0",
55 | "moment": "^2.29.3",
56 | "node-sass": "^7.0.1",
57 | "popper.js": "^1.16.1",
58 | "prismjs": "^1.28.0",
59 | "rollup-plugin-vue": "^6.0.0",
60 | "sass-loader": "^13.0.0",
61 | "tailwindcss": "^2.2.19",
62 | "ts-jest": "^27.0.0",
63 | "typescript": "~4.7.2",
64 | "vue-class-component": "^7.2.6",
65 | "vue-jest": "^3.0.7",
66 | "vue-loading-overlay": "^3.4.2",
67 | "vue-markdown-loader": "^2.5.0",
68 | "vue-property-decorator": "^9.1.2",
69 | "vue-router": "^3.1.3",
70 | "vue-select": "^3.18.3",
71 | "vue-sweetalert2": "^5.0.5",
72 | "vue-template-compiler": "^2.6.14",
73 | "vuex": "^3.1.1",
74 | "vuex-persistedstate": "^4.1.0"
75 | },
76 | "files": [
77 | "dist/*",
78 | "src/*"
79 | ],
80 | "browserslist": [
81 | "> 1%",
82 | "last 2 versions",
83 | "not ie <= 8"
84 | ]
85 | }
86 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | // postcss.config.js
2 | const autoprefixer = require('autoprefixer');
3 | const tailwindcss = require('tailwindcss');
4 |
5 | const postcssPurgecss = require(`@fullhuman/postcss-purgecss`);
6 |
7 | const purgecss = postcssPurgecss({
8 | // Specify the paths to all of the template files in your project.
9 | content: [
10 | './public/**/*.html',
11 | './documentation/**/*.vue',
12 | ],
13 | // Include any special characters you're using in this regular expression.
14 | // See: https://tailwindcss.com/docs/controlling-file-size/#understanding-the-regex
15 | defaultExtractor: content => content.match(/[\w-/:]+(?
2 |
3 |
4 |
5 | Single Page Apps for GitHub Pages
6 |
7 |
8 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Laravel Vue Datatable
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
44 |
45 |
46 |
47 | We're sorry but laravel-vue-datatable doesn't work properly without JavaScript enabled. Please enable it to continue.
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/components/DataTableCell.vue:
--------------------------------------------------------------------------------
1 |
100 |
--------------------------------------------------------------------------------
/src/components/DataTableFilters.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
11 | {{records}}
12 |
13 |
14 |
15 |
16 |
21 |
22 |
23 |
24 |
25 |
86 |
--------------------------------------------------------------------------------
/src/components/DataTableTh.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/components/Table.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
9 |
10 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
91 |
--------------------------------------------------------------------------------
/src/functions/MergeClasses.ts:
--------------------------------------------------------------------------------
1 | export default function mergeClasses(...classlists) {
2 | const classes = [];
3 |
4 | for (let classlist in classlists) {
5 | if (classlists.hasOwnProperty(classlist)) {
6 | let list = classlists[`${classlist}`];
7 |
8 | if (typeof list === "string") {
9 | classes.push(list);
10 | } else if (Array.isArray(list)) {
11 | classes.push(...list);
12 | } else if (typeof list === "object") {
13 | for (let cls in list) {
14 | if (list.hasOwnProperty(cls) &&
15 | typeof list[`${cls}`] !== "object" &&
16 | list[`${cls}`] &&
17 | cls !== "!override") {
18 | classes.push(`${cls}`);
19 | }
20 | }
21 | }
22 | }
23 | }
24 |
25 | return [...new Set(classes)].join(" ");
26 | };
27 |
--------------------------------------------------------------------------------
/src/mixins/UrlFilters.js:
--------------------------------------------------------------------------------
1 | export default {
2 | methods: {
3 | getURLParameter(name) {
4 | return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
5 | },
6 | IsValidJSONString(str) {
7 | try {
8 | JSON.parse(str);
9 | } catch (e) {
10 | return false;
11 | }
12 | return true;
13 | },
14 | checkParameters(tableData) {
15 | if (this.addFiltersToUrl) {
16 | let localStorage = window.localStorage;
17 |
18 | Object.keys(tableData).forEach(filter => {
19 | if (this.getURLParameter(filter)) {
20 | let value = this.getURLParameter(filter);
21 |
22 | if (! isNaN(value)) {
23 | this.tableData[filter] = Number(value);
24 | }
25 | else if (this.IsValidJSONString(value)) {
26 | this.tableData.filters = JSON.parse(value);
27 | }
28 | else {
29 | this.tableData[filter] = value;
30 | }
31 |
32 | } else if (localStorage.getItem(this.$options.name + "_" + filter)){
33 | let value = localStorage.getItem(this.$options.name + "_" + filter);
34 |
35 | if (! isNaN(value)) {
36 | this.tableData[filter] = Number(value);
37 | }
38 | else if (this.IsValidJSONString(value)) {
39 | this.tableData.filters = JSON.parse(value);
40 | }
41 | else {
42 | this.tableData[filter] = value;
43 | }
44 | }
45 | });
46 |
47 | this.updateParameters(this.tableData);
48 | }
49 | },
50 | updateParameters(tableData) {
51 |
52 | let newFilters = {};
53 |
54 | Object.keys(tableData).forEach(filter => {
55 | if (this.tableData[filter]) {
56 | newFilters[filter] = JSON.stringify(this.tableData[filter]);
57 | } else {
58 | newFilters[filter] = this.tableData[filter];
59 | }
60 | });
61 |
62 | for (let filter in newFilters) {
63 | localStorage.setItem(this.$options.name + "_" + filter, newFilters[filter]);
64 | }
65 |
66 | let parameters = Object.keys(newFilters).map(function(k) {
67 | return encodeURIComponent(k) + '=' + encodeURIComponent(newFilters[k])
68 | }).join('&')
69 |
70 | let url = document.URL.split('?')[0];
71 |
72 | window.history.pushState(newFilters, 'Title', url + "?" + parameters);
73 | },
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/plugin.ts:
--------------------------------------------------------------------------------
1 | import DataTable from "./components/DataTable.vue";
2 | import { TailablePagination } from 'tailable-pagination';
3 | import DataTableCell from "./components/DataTableCell.vue";
4 |
5 | export default {
6 | install(Vue) {
7 | Vue.component("data-table", DataTable);
8 | Vue.component("data-table-cell", DataTableCell);
9 | Vue.component("tailable-pagination", TailablePagination);
10 | },
11 | };
12 |
13 | export { DataTable, DataTableCell };
14 |
--------------------------------------------------------------------------------
/src/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 |
2 | import Vue, { VNode } from 'vue';
3 |
4 | declare global {
5 | namespace JSX {
6 | // tslint:disable no-empty-interface
7 | interface Element extends VNode {}
8 | // tslint:disable no-empty-interface
9 | interface ElementClass extends Vue {}
10 | interface IntrinsicElements {
11 | [elem: string]: any;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue';
3 | export default Vue;
4 | }
5 |
--------------------------------------------------------------------------------
/src/themes/Bootstrap.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | "table-container": {
3 | "table-responsive": true
4 | },
5 | "table": {
6 | "table": true,
7 | "table-striped": true,
8 | "border": true
9 | },
10 | "t-head": {},
11 | "t-body": {},
12 | "td": {},
13 | "th": {}
14 | }
--------------------------------------------------------------------------------
/src/themes/Tailwind.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | "container": {
3 | "w-full": true
4 | },
5 | "table-container": {
6 | "w-full overflow-x-auto rounded-t": true
7 | },
8 | "table": {
9 | "min-w-full": true,
10 | },
11 | "t-head": {
12 | "bg-gray-100": true,
13 | "border": true,
14 | },
15 | "t-body": {
16 | "bg-white border-r border-l border-b": true,
17 | },
18 | "t-body-tr": {
19 | "bg-white even:bg-gray-100": true,
20 | },
21 | "td": {
22 | "px-4 py-3 whitespace-no-wrap border-b border-gray-200": true,
23 | },
24 | "th": {
25 | "p-4 text-xs whitespace-no-wrap hover:cursor-pointer text-left": true,
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/src/validators/data-table-framework.ts:
--------------------------------------------------------------------------------
1 | export default (value) => {
2 | return [
3 | 'bootstrap',
4 | 'tailwind',
5 | ].indexOf(value) !== -1;
6 | };
7 |
--------------------------------------------------------------------------------
/src/validators/data-table-order-dir.ts:
--------------------------------------------------------------------------------
1 | export default (value) => {
2 | return [
3 | 'asc',
4 | 'desc',
5 | ].indexOf(value) !== -1;
6 | };
7 |
--------------------------------------------------------------------------------
/src/validators/data-table-theme.ts:
--------------------------------------------------------------------------------
1 | export default (value) => {
2 | return [
3 | 'light',
4 | 'dark',
5 | ].indexOf(value) !== -1;
6 | };
7 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | theme: {
3 | minWidth: {
4 | '0': '0',
5 | '1/6': '16.666667%',
6 | '1/2': '50%',
7 | '3/4': '75%',
8 | 'full': '100%',
9 | },
10 | extend: {},
11 | },
12 | variants: {
13 | opacity: ['disabled'],
14 | cursor: ['disabled', 'hover'],
15 | zIndex: ['focus'],
16 | backgroundColor: ['hover', 'focus', 'even'],
17 | },
18 | plugins: [],
19 | }
20 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": false,
6 | "jsx": "preserve",
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "experimentalDecorators": true,
10 | "esModuleInterop": true,
11 | "allowSyntheticDefaultImports": true,
12 | "sourceMap": true,
13 | "baseUrl": ".",
14 | "noImplicitThis": true,
15 | "types": [
16 | "webpack-env",
17 | "jest"
18 | ],
19 | "paths": {
20 | "@/*": [
21 | "src/*"
22 | ]
23 | },
24 | "lib": [
25 | "esnext",
26 | "dom",
27 | "dom.iterable",
28 | "scripthost"
29 | ]
30 | },
31 | "include": [
32 | "src/**/*.ts",
33 | "src/**/*.tsx",
34 | "src/**/*.vue",
35 | "tests/**/*.ts",
36 | "tests/**/*.tsx"
37 | ],
38 | "exclude": [
39 | "node_modules"
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | module.exports = {
4 | publicPath: `/laravel-vue-datatable`,
5 | outputDir: path.resolve(__dirname, "./docs"),
6 | chainWebpack: config => {
7 | config.module.rule('md')
8 | .test(/\.md/)
9 | .use('vue-loader')
10 | .loader('vue-loader')
11 | .end()
12 | .use('vue-markdown-loader')
13 | .loader('vue-markdown-loader/lib/markdown-compiler')
14 | .options({
15 | raw: true
16 | })
17 | }
18 | }
19 |
--------------------------------------------------------------------------------