Just in case anyone wants a dynamic table with what's offered above and with multiple props to search, here it is.
<template>
<div>
<el-table
:data="displayData"
:default-sort="tableSort ? { prop: tableSortBy, order: tableSortOrder } : { prop: '', order: '' }"
:height="tableHeight"
:table-layout="tableLayout"
highlight-current-row
@row-click="onRowClick"
>
<el-table-column
class="tw-cursor-pointer"
v-for="column in columns"
:key="column.label"
:label="column.label"
:prop="column.prop"
:formatter="column.formatter"
:min-width="column.minWidth"
:sortable="column.sortable"
>
<template #default="scope">
<div v-if="column.funcProp" v-html="column.funcProp(scope.row)"></div>
</template>
</el-table-column>
<el-table-column width="300" align="right">
<template #header>
<div class="tw-mt-1 tw-relative tw-rounded-md tw-shadow-sm">
<div class="tw-absolute tw-inset-y-0 tw-left-0 tw-pl-3 tw-flex tw-items-center tw-pointer-events-none">
<SearchIcon class="tw-h-5 tw-w-5 tw-text-gray-400" aria-hidden="true" />
</div>
<input
v-model="search"
type="search"
class="focus:tw-ring-indigo-500 focus:tw-border-indigo-500 tw-block tw-w-full tw-pl-10 sm:tw-text-sm tw-border-gray-300 tw-rounded-md"
:placeholder="`Search by ${searchBy !== '' ? searchBy : 'name'}`"
/>
</div>
</template>
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.row)">Edit</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.row)">Delete</el-button>
</template>
</el-table-column>
</el-table>
<div class="tw-mt-4">
<el-pagination
background
@size-change="changePerPage"
@current-change="changeCurrentPage"
@currentPage="currentPage"
:page-size="perPage"
:page-sizes="[20, 30, 40, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
</div>
</div>
</template>
<script>
import { SearchIcon } from '@heroicons/vue/solid'
export default {
components: { SearchIcon },
props: {
data: Array,
columns: Array,
tableLayout: {
type: String,
default: 'auto',
required: false,
},
tableSort: {
type: Boolean,
default: false,
required: false,
},
tableSortBy: {
type: String,
default: '',
required: false,
},
tableSortOrder: {
type: String,
default: 'asc',
required: false,
},
tableHeight: {
type: String,
default: '70vh',
required: false,
},
searchBy: {
type: Array,
default: ['name'],
required: false,
},
},
data() {
return {
filtered: [],
search: '',
page: 1,
currentPage: 1,
perPage: 20,
total: 0,
}
},
computed: {
displayData() {
if (this.search == null) return this.data
this.filtered = this.data.filter(
(data) =>
!this.search ||
this.searchBy.some((item) => data[item].toString().toLowerCase().includes(this.search.toLowerCase()))
)
this.total = this.filtered.length
return this.filtered.slice(this.perPage * this.currentPage - this.perPage, this.perPage * this.currentPage)
},
},
methods: {
onRowClick(row) {
this.$emit('rowclick', row)
},
handleEdit(row) {
this.$emit('edit', row)
},
handleDelete(row) {
this.$emit('delete', row)
},
changeCurrentPage(val) {
this.currentPage = val
},
changePerPage(val) {
this.perPage = val
},
},
}
</script>
Your component calling the Dynamic table component
data() {
return {
columns: [
{
label: 'Name',
prop: 'name',
sortable: true,
},
{
label: 'Email',
prop: 'email',
sortable: true,
},
]}
},
methods: {
handleEdit(row) {
console.log(row)
},
handleDelete(row) {
console.log(row.id)
},
},
<Table
:data="data"
:columns="columns"
table-layout="fixed"
table-height="70vh"
@edit="handleEdit"
@delete="handleDelete"
@rowclick="handleEdit"
:search-active="true"
:table-sort="true"
:table-sort-by="'name'"
:table-sort-order="'asc'"
:search-by="['name', 'email']"
/>
You can now feed data to your dynamic table and user over and over!!
I'm sure there are things to improve, but that's up to you now :)