Last active
January 13, 2018 19:21
-
-
Save itzikbenh/5e7dea5ea78ee5587f544a4f40f7e6a2 to your computer and use it in GitHub Desktop.
Vue datatables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<style> | |
thead { | |
.sorting { | |
background-image: url('DataTables-1.10.15/images/sort_both.png'); | |
background-repeat: no-repeat; | |
background-position: center right; | |
} | |
.sorting_asc { | |
background-image: url('DataTables-1.10.15/images/sort_asc.png'); | |
background-repeat: no-repeat; | |
background-position: center right; | |
} | |
.sorting_desc { | |
background-image: url('DataTables-1.10.15/images/sort_desc.png'); | |
background-repeat: no-repeat; | |
background-position: center right; | |
} | |
} | |
</style> | |
<template> | |
<table class="table is-bordered data-table""> | |
<thead> | |
<tr> | |
<th v-for="column in columns" v-if="!(column.hasOwnProperty('orderable') && !column.orderable)" :key="column.name" @click="$emit('sort', column.name)" | |
v-show="!(column.hasOwnProperty('visible') && !column.visible)" | |
:class="sortKey === column.name ? (sortOrders[column.name] > 0 ? 'sorting_asc' : 'sorting_desc') : 'sorting'" | |
:style="'width:'+column.width+';'+'cursor:pointer;'"> | |
{{column.label}} | |
</th> | |
<th v-else :style="'width:'+column.width" :key="column.name" | |
v-show="!(column.hasOwnProperty('visible') && !column.visible)"> | |
{{column.label}} | |
</th> | |
</tr> | |
</thead> | |
<slot></slot> | |
</table> | |
</template> | |
<script> | |
export default { | |
props: ['columns', 'sortOrders', 'sortKey'], | |
} | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div> | |
<div class="table-filters"> | |
<div class="textSearch"> | |
<input type="text" class="input" v-model="search" @input="resetPagination();" placeholder="Search Table"> | |
</div> | |
<div class="flex-right"> | |
<excel-export :data="filteredDff" :columns="columns" filename="data"></excel-export> | |
<select v-model="length" @change="resetPagination()"> | |
<option value="20">20</option> | |
<option value="150">150</option> | |
<option value="300">300</option> | |
<option value="450">450</option> | |
<option value="2000">2000</option> | |
<option value="6000">6000</option> | |
<option value="10000">10000</option> | |
</select> | |
</div> | |
</div> | |
<datatable :columns="columns" :sortKey="sortKey" :sortOrders="sortOrders" @sort="sortBy"> | |
<tbody> | |
<tr v-for="d in paginated" :key="d.user_id"> | |
<td>{{ d.first_name }}</td> | |
<td>{{ d.last_name }}</td> | |
<td>{{ d.email }}</td> | |
<td>{{ d.company }}</td> | |
<td>{{ d.job_title }}</td> | |
<td>{{ d.file_description }}</td> | |
<td>{{ d.created_at | niceDate }}</td> | |
</tr> | |
<tr v-if="!filteredDff.length"> | |
<td class="text-center" colspan="100%">No results were found.</td> | |
</tr> | |
</tbody> | |
</datatable> | |
<pagination :pagination="pagination" :client="true" :filtered="filteredDff" | |
@paginate:prev="--pagination.currentPage" | |
@paginate:next="pagination.currentPage++"> | |
</pagination> | |
</div> | |
</template> | |
<script> | |
import {helpers} from '../mixins/helpers'; | |
export default { | |
mixins: [helpers], | |
props: ['dff'], | |
data() { | |
let sortOrders = {}; | |
let columns = [ | |
{ width: '12%', label: 'First Name', orderable: true, name: 'first_name' }, | |
{ width: '12%', label: 'Last Name', orderable: true, name: 'last_name' }, | |
{ width: '20%', label: 'Email', orderable: true, name: 'email'}, | |
{ width: '10%', label: 'Company', orderable: true, name: 'company'}, | |
{ width: '8%', label: 'Job Title', orderable: true, name: 'job_title'}, | |
{ width: '12%', label: 'File Description', orderable: true, name: 'file_description'}, | |
{ width: '8%', label: 'Date', orderable: true, name: 'created_at', type: 'date' }, | |
]; | |
columns.forEach((column) => { | |
if (column.orderable) { | |
sortOrders[column.name] = -1; | |
} | |
}); | |
return { | |
columns: columns, | |
sortKey: 'created_at', | |
sortOrders: sortOrders, | |
search: '', | |
length: 20, | |
pagination: { | |
prevPage: '', | |
currentPage: 1, | |
nextPage: '', | |
from: '', | |
to: '', | |
total: this.dff.length, | |
}, | |
} | |
}, | |
methods: { | |
paginate(array, length, pageNumber) { | |
this.pagination.from = array.length ? ((pageNumber - 1) * length) + 1 : ' '; | |
this.pagination.to = pageNumber * length > array.length ? array.length : pageNumber * length; | |
this.pagination.prevPage = pageNumber > 1 ? pageNumber : ''; | |
this.pagination.nextPage = array.length > this.pagination.to ? pageNumber + 1 : ''; | |
return array.slice((pageNumber - 1) * length, pageNumber * length); | |
}, | |
resetPagination() { | |
this.pagination.currentPage = 1; | |
this.pagination.prevPage = ''; | |
this.pagination.nextPage = ''; | |
}, | |
sortBy(key) { | |
this.resetPagination(); | |
this.sortKey = key; | |
this.sortOrders[key] = this.sortOrders[key] * -1; | |
}, | |
}, | |
computed: { | |
filteredDff() { | |
let dff = this.dff; | |
if (this.search) { | |
dff = this.searchData(dff, this.columns, this.search); | |
} | |
let sortKey = this.sortKey; | |
let order = this.sortOrders[sortKey] || 1; | |
if (sortKey) { | |
dff = this.sortData(dff, this.columns, sortKey, order); | |
} | |
return dff; | |
}, | |
paginated() { | |
return this.paginate(this.filteredDff, this.length, this.pagination.currentPage); | |
}, | |
} | |
} | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const helpers = { | |
methods: { | |
getIndex(array, key, value) { | |
return array.findIndex(i => i[key] == value) | |
}, | |
leaf(obj, path) { | |
path = path.split('.'); | |
let res = obj; | |
for (let i = 0; i < path.length; i++) { | |
if (res[path[i]]) { | |
res = res[path[i]] | |
} else { | |
return ''; | |
} | |
} | |
return res; | |
}, | |
sortData(data, columns, sortKey, order) { | |
return data.slice().sort((a, b) => { | |
let index = this.getIndex(columns, 'name', sortKey); | |
a = String(this.leaf(a, sortKey)).toLowerCase(); | |
b = String(this.leaf(b, sortKey)).toLowerCase(); | |
if (columns[index].type && columns[index].type === 'date') { | |
return (a === b ? 0 : new Date(a).getTime() > new Date(b).getTime() ? 1 : -1) * order; | |
} else if (columns[index].type && columns[index].type === 'number') { | |
return (+a === +b ? 0 : +a > +b ? 1 : -1) * order; | |
} else { | |
return (a === b ? 0 : a > b ? 1 : -1) * order; | |
} | |
}) | |
}, | |
searchData(data, columns, search) { | |
return data.filter((row) => { | |
return Object.keys(columns).some((key) => { | |
if (!(key > -1) || (columns[key].hasOwnProperty('visible') && !columns[key].visible) || (columns[key].hasOwnProperty('searchable') && !columns[key].searchable)) { | |
return false; | |
} | |
return String(this.leaf(row, columns[key].name)).toLowerCase().indexOf(search.toLowerCase()) > -1; | |
}); | |
}); | |
}, | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<nav class="pagination" v-if="!client"> | |
<span class="page-stats">{{pagination.from}} - {{pagination.to}} of {{pagination.total}}</span> | |
<a v-if="pagination.prevPage" class="prev-page" @click="$emit('paginate:prev');"> | |
<span class="dashicons dashicons-arrow-left"></span> | |
</a> | |
<a class="prev-page" v-else :disabled="true"> | |
<span class="dashicons dashicons-arrow-left"></span> | |
</a> | |
<a v-if="pagination.nextPage" class="next-page" @click="$emit('paginate:next');"> | |
<span class="dashicons dashicons-arrow-right"></span> | |
</a> | |
<a class="next-page" v-else :disabled="true"> | |
<span class="dashicons dashicons-arrow-right"></span> | |
</a> | |
</nav> | |
<nav class="pagination" v-else> | |
<span class="page-stats"> | |
{{pagination.from}} - {{pagination.to}} of {{filtered.length}} | |
<span v-if="filtered.length < pagination.total">(filtered from {{pagination.total}} total entries)</span> | |
</span> | |
<a v-if="pagination.prevPage" class="prev-page" @click="$emit('paginate:prev');"> | |
<span class="dashicons dashicons-arrow-left"></span> | |
</a> | |
<a class="prev-page" v-else :disabled="true"> | |
<span class="dashicons dashicons-arrow-left"></span> | |
</a> | |
<a v-if="pagination.nextPage" class="next-page" @click="$emit('paginate:next');"> | |
<span class="dashicons dashicons-arrow-right"></span> | |
</a> | |
<a class="next-page" v-else :disabled="true"> | |
<span class="dashicons dashicons-arrow-right"></span> | |
</a> | |
</nav> | |
</template> | |
<script> | |
export default { | |
props: ['pagination', 'client', 'filtered'], | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment