Created
June 24, 2021 07:39
-
-
Save arwinvdv/1e35a9b223732bf874b5d4a86f72fc1c to your computer and use it in GitHub Desktop.
A very simple vue 3 table
This file contains hidden or 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> | |
<table> | |
<thead> | |
<tr> | |
<th v-for="(column, index) in columns" :key="`col-${index}`" @click="sort(column.field)">{{ column.label }}</th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr v-for="(row, index_row) in sortedRows" :key="'row' + index_row + uid"> | |
<template v-if="index_row >= max_per_page * (current_page) && index_row < max_per_page * (current_page+1)"> | |
<td v-for="(column, index_col) in columns" :key="`rowcol-${index_row}-${index_col}`"> | |
<template v-if="column.slot === undefined || column.slot === ''">{{ row[column.field] }}</template> | |
<slot v-else :name="column.slot" :row="row"></slot> | |
</td> | |
</template> | |
</tr> | |
</tbody> | |
</table> | |
<div class="flex text-sm justify-center items-center gap-2 p-2"> | |
<button class="btn btn-secondary" @click="current_page > 0 ? current_page-- : null"><</button> | |
<span>Page {{ current_page + 1 }} of {{ nrOfPages }}</span> | |
<button class="btn btn-secondary" @click="current_page < (nrOfPages-1) ? current_page++ : null">></button> | |
</div> | |
</div> | |
</template> | |
<script> | |
export default { | |
name: 'SimpleTable', | |
props: { | |
rows: { | |
type: Array, | |
default: [], | |
required: true | |
}, | |
columns: { | |
type: Array, | |
default: [], | |
required: true | |
} | |
}, | |
data: function () { | |
return { | |
current_sort: 'name', | |
current_sort_dir: 'asc', | |
current_page: 0, | |
max_per_page: 50, | |
uid: '', | |
} | |
}, | |
computed: { | |
nrOfPages() { | |
return Math.ceil(this.rows.length / this.max_per_page) | |
}, | |
sortedRows() { | |
return this.rows.sort((a, b) => { | |
let modifier = 1 | |
if (this.current_sort_dir === 'desc') modifier = -1 | |
if (a[this.current_sort] < b[this.current_sort]) return -1 * modifier | |
if (a[this.current_sort] > b[this.current_sort]) return 1 * modifier | |
return 0 | |
}) | |
} | |
}, | |
watch: { | |
sortedRows: { | |
immediate: true, | |
handler(newVal, oldVal) { | |
this.uid = Date.now() // fix for index v-for | |
} | |
} | |
}, | |
methods: { | |
sort: function (s) { | |
//if s == current sort reverse | |
if (s === this.current_sort) { | |
this.current_sort_dir = this.current_sort_dir === 'asc' ? 'desc' : 'asc' | |
} | |
this.current_sort = s | |
this.uid = Date.now() // Fix for index v-for | |
}, | |
} | |
} | |
</script> | |
===================== | |
HOW TO USE: | |
<template> | |
<simple-table :columns="columns" :rows="rows"> | |
<template v-slot:name="slotProps"> | |
<a @click="">{{ slotProps.row.name }}</a> | |
</template> | |
<template v-slot:action> | |
<button class="btn btn-success" @click="">Open</button> | |
</template> | |
</simple-table> | |
</template> | |
<script> | |
import SimpleTable from '../components/vue-3-simple-table.vue' | |
export default { | |
components: {SimpleTable}, | |
data: function () { | |
return { | |
columns: [ | |
{ | |
field: 'name', | |
label: 'Name', | |
slot: 'name', | |
}, | |
{ | |
field: 'description', | |
label: 'Description', | |
}, | |
{ | |
field: '', | |
label: 'Action', | |
slot: 'action', | |
}, | |
], | |
rows: [ | |
{ | |
name: 'Row 1', | |
description: 'Some description', | |
}, | |
{ | |
name: 'Row 2', | |
description: 'Some description 2', | |
} | |
], | |
} | |
} | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment