Files
oa/documentation/flex-table/v-flex-table-wrapper-documentation.md
2025-05-24 01:49:48 +09:00

175 lines
4.9 KiB
Markdown

### 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.
<!--code-->
```vue
<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>
```
<!--/code-->