Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Table): extends core options and support other options like pagination #3177

Merged
merged 15 commits into from
Feb 5, 2025
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,6 @@ const columns: TableColumn<Payment>[] = [{
}
}]

const table = useTemplateRef('table')

const globalFilter = ref('45')
</script>

Expand Down
174 changes: 174 additions & 0 deletions docs/app/components/content/examples/table/TablePaginationExample.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
<script setup lang="ts">
import { getPaginationRowModel } from '@tanstack/vue-table'
import type { TableColumn } from '@nuxt/ui'

const table = useTemplateRef('table')

type Payment = {
id: string
date: string
email: string
amount: number
}
const data = ref<Payment[]>([{
id: '4600',
date: '2024-03-11T15:30:00',
email: '[email protected]',
amount: 594
}, {
id: '4599',
date: '2024-03-11T10:10:00',
email: '[email protected]',
amount: 276
}, {
id: '4598',
date: '2024-03-11T08:50:00',
email: '[email protected]',
amount: 315
}, {
id: '4597',
date: '2024-03-10T19:45:00',
email: '[email protected]',
amount: 529
}, {
id: '4596',
date: '2024-03-10T15:55:00',
email: '[email protected]',
amount: 639
}, {
id: '4595',
date: '2024-03-10T13:20:00',
email: '[email protected]',
amount: 428
}, {
id: '4594',
date: '2024-03-10T11:05:00',
email: '[email protected]',
amount: 673
}, {
id: '4593',
date: '2024-03-09T22:15:00',
email: '[email protected]',
amount: 382
}, {
id: '4592',
date: '2024-03-09T20:30:00',
email: '[email protected]',
amount: 547
}, {
id: '4591',
date: '2024-03-09T18:45:00',
email: '[email protected]',
amount: 291
}, {
id: '4590',
date: '2024-03-09T16:20:00',
email: '[email protected]',
amount: 624
}, {
id: '4589',
date: '2024-03-09T14:10:00',
email: '[email protected]',
amount: 438
}, {
id: '4588',
date: '2024-03-09T12:05:00',
email: '[email protected]',
amount: 583
}, {
id: '4587',
date: '2024-03-09T10:30:00',
email: '[email protected]',
amount: 347
}, {
id: '4586',
date: '2024-03-09T08:15:00',
email: '[email protected]',
amount: 692
}, {
id: '4585',
date: '2024-03-08T23:40:00',
email: '[email protected]',
amount: 419
}, {
id: '4584',
date: '2024-03-08T21:25:00',
email: '[email protected]',
amount: 563
}, {
id: '4583',
date: '2024-03-08T19:50:00',
email: '[email protected]',
amount: 328
}, {
id: '4582',
date: '2024-03-08T17:35:00',
email: '[email protected]',
amount: 647
}, {
id: '4581',
date: '2024-03-08T15:20:00',
email: '[email protected]',
amount: 482
}])
const columns: TableColumn<Payment>[] = [{
accessorKey: 'id',
header: '#',
cell: ({ row }) => `#${row.getValue('id')}`
}, {
accessorKey: 'date',
header: 'Date',
cell: ({ row }) => {
return new Date(row.getValue('date')).toLocaleString('en-US', {
day: 'numeric',
month: 'short',
hour: '2-digit',
minute: '2-digit',
hour12: false
})
}
}, {
accessorKey: 'email',
header: 'Email'
}, {
accessorKey: 'amount',
header: () => h('div', { class: 'text-right' }, 'Amount'),
cell: ({ row }) => {
const amount = Number.parseFloat(row.getValue('amount'))
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'EUR'
}).format(amount)
return h('div', { class: 'text-right font-medium' }, formatted)
}
}]

const pagination = ref({
pageIndex: 0,
pageSize: 5
})
</script>

<template>
<div class="w-full space-y-4 pb-4">
<UTable
ref="table"
v-model:pagination="pagination"
:data="data"
:columns="columns"
:pagination-options="{
getPaginationRowModel: getPaginationRowModel()
}"
class="flex-1"
/>

<div class="flex justify-center border-t border-[var(--ui-border)] pt-4">
<UPagination
:default-page="(table?.tableApi?.getState().pagination.pageIndex || 0) + 1"
:items-per-page="table?.tableApi?.getState().pagination.pageSize"
:total="table?.tableApi?.getFilteredRowModel().rows.length"
@update:page="(p) => table?.tableApi?.setPageIndex(p - 1)"
/>
</div>
</div>
</template>
21 changes: 20 additions & 1 deletion docs/content/3.components/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ You can use the `column-pinning` prop to control the pinning state of the column

### With column visibility

You can add use [DropdownMenu](/components/dropdown-menu) component to toggle the visibility of the columns using the TanStack Table [Column Visibility APIs](https://tanstack.com/table/latest/docs/api/features/column-visibility).
You can use a [DropdownMenu](/components/dropdown-menu) component to toggle the visibility of the columns using the TanStack Table [Column Visibility APIs](https://tanstack.com/table/latest/docs/api/features/column-visibility).

::component-example
---
Expand Down Expand Up @@ -391,6 +391,25 @@ class: '!p-0'
You can use the `global-filter` prop to control the global filter state (can be binded with `v-model`).
::

### With pagination

You can use a [Pagination](/components/pagination) component to control the pagination state using the [Pagination APIs](https://tanstack.com/table/latest/docs/api/features/pagination).

There are different pagination approaches as explained in [Pagination Guide](https://tanstack.com/table/latest/docs/guide/pagination#pagination-guide). In this example, we use client-side pagination so we need to manually pass `getPaginationRowModel()`{lang="ts-type"} function.

::component-example
---
prettier: true
collapse: true
name: 'table-pagination-example'
class: '!p-0'
---
::

::tip
You can use the `pagination` prop to control the pagination state (can be binded with `v-model`).
::

### With fetched data

You can fetch data from an API and use them in the Table.
Expand Down
18 changes: 14 additions & 4 deletions playground/app/pages/components/table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { h, resolveComponent } from 'vue'
import { upperFirst } from 'scule'
import type { TableColumn } from '@nuxt/ui'
import { getPaginationRowModel } from '@tanstack/vue-table'

const UButton = resolveComponent('UButton')
const UCheckbox = resolveComponent('UCheckbox')
Expand Down Expand Up @@ -269,6 +270,11 @@ const columnPinning = ref({
right: ['actions']
})

const pagination = ref({
pageIndex: 0,
pageSize: 10
})

function randomize() {
data.value = [...data.value].sort(() => Math.random() - 0.5)
}
Expand Down Expand Up @@ -322,11 +328,15 @@ onMounted(() => {
:columns="columns"
:column-pinning="columnPinning"
:loading="loading"
sticky
:pagination="pagination"
:pagination-options="{
getPaginationRowModel: getPaginationRowModel()
}"
:ui="{
tr: 'divide-x divide-[var(--ui-border)]'
}"
class="border border-[var(--ui-border-accented)] rounded-[var(--ui-radius)] flex-1"
sticky
class="border border-[var(--ui-border-accented)] rounded-[var(--ui-radius)]"
>
<template #expanded="{ row }">
<pre>{{ row.original }}</pre>
Expand All @@ -339,7 +349,7 @@ onMounted(() => {
{{ table?.tableApi?.getFilteredRowModel().rows.length || 0 }} row(s) selected.
</div>

<!-- <div class="flex items-center gap-1.5">
<div class="flex items-center gap-1.5">
<UButton
color="neutral"
variant="outline"
Expand All @@ -356,7 +366,7 @@ onMounted(() => {
>
Next
</UButton>
</div> -->
</div>
</div>
</div>
</template>
Loading