mirror of
https://git.hmsn.ink/kospo/svcm/oa.git
synced 2026-03-20 08:03:34 +09:00
4.9 KiB
4.9 KiB
VFlexTableWrapper
You can wrap <VFlexTable /> using <VFlexTableWrapper /> to render large
amount of data.
This will also enable sorting, searching and paginating through the data.
Instead of providing data and columns properties to <VFlexTable />,
you just have to declare them to <VFlexTableWrapper />.
In addition to the base columns settings, searchable, sortable attributes
can be used to enable search and sorting. Of course, custom sort and filter
function can be used. To easily customize your table, <VFlexPagination />, <VFlexTableToolbar>
and <VFlexTableSortColumn> components can be used
to display controls for pagination and search.
Check the markup for more details about usage.
<script setup lang="ts">
import type {
VFlexTableWrapperSortFunction,
VFlexTableWrapperFilterFunction,
} from '/@src/components/base/table/VFlexTableWrapper.vue'
import { users } from '/@src/data/layouts/card-grid-v1'
type User = (typeof users)[0]
// duplicate user data to grow the array
const data: User[] = []
for (let i = 0; i < 1000; i++) {
data.push(...users)
}
// this is a sample for custom sort function
const locationSorter: VFlexTableWrapperSortFunction<User> = ({ order, a, b }) => {
if (order === 'asc') {
return a.location.localeCompare(b.location)
}
else if (order === 'desc') {
return b.location.localeCompare(a.location)
}
return 0
}
// this is a sample for custom filter function
const userFilter: VFlexTableWrapperFilterFunction<User> = ({ searchTerm, row }) => {
if (!searchTerm) {
return true
}
// search either in the name or the bio
return (
row.name.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase())
|| row.bio.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase())
)
}
const columns = {
name: {
label: 'Username',
media: true,
grow: true,
searchable: true,
sortable: true,
filter: userFilter,
},
location: {
label: 'Location',
sortable: true,
searchable: true,
sort: locationSorter,
},
role: 'Role',
} as const
</script>
<template>
<VFlexTableWrapper :columns="columns" :data="data">
<!--
Here we retrieve the internal wrapperState.
Note that we can not destructure it
-->
<template #default="wrapperState">
<!-- We can place any content inside the default slot-->
<VFlexTableToolbar>
<template #left>
<!-- We can bind wrapperState.searchInput to any input -->
<VField>
<VControl icon="lucide:search">
<input
v-model="wrapperState.searchInput"
type="text"
class="input is-rounded"
placeholder="Filter..."
>
</VControl>
</VField>
</template>
<template #right>
<!-- We can also bind wrapperState.limit -->
<VField>
<VControl>
<div class="select is-rounded">
<select v-model="wrapperState.limit">
<option :value="1">
1 results per page
</option>
<option :value="10">
10 results per page
</option>
<option :value="15">
15 results per page
</option>
<option :value="25">
25 results per page
</option>
<option :value="50">
50 results per page
</option>
</select>
</div>
</VControl>
</VField>
</template>
</VFlexTableToolbar>
<!--
The VFlexTable "data" and "columns" props
will be inherited from parent VFlexTableWrapper
-->
<VFlexTable rounded>
<!-- Custom "name" cell content -->
<template #body-cell="{ row, column }">
<template v-if="column.key === 'name'">
<VAvatar
size="medium"
:picture="row.medias.avatar"
:badge="row.medias.badge"
:initials="row.initials"
/>
<div>
<span class="dark-text" :title="row.name">
{{ row?.shortname }}
</span>
<VTextEllipsis
width="280px"
class="light-text"
:title="row.bio"
>
<small>{{ row?.bio }}</small>
</VTextEllipsis>
</div>
</template>
</template>
</VFlexTable>
<!-- Table Pagination with wrapperState.page binded-->
<VFlexPagination
v-model:current-page="wrapperState.page"
class="mt-6"
:item-per-page="wrapperState.limit"
:total-items="wrapperState.total"
:max-links-displayed="5"
no-router
/>
</template>
</VFlexTableWrapper>
</template>