Skip to content

Commit 3edc8d2

Browse files
committed
feat: add backend pagination for the afcl table
1 parent 8876964 commit 3edc8d2

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

adminforth/documentation/docs/tutorial/03-Customization/15-afcl.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,7 @@ const isoFlagToEmoji = (iso) => iso.toUpperCase().replace(/./g, char => String.f
797797

798798

799799

800-
## Pagination
800+
### Pagination
801801

802802
Table provides front-end side pagination. You can set `pageSize` (default is 10) to set how many rows to show per page.
803803
If there is less then `pageSize` rows, pagination will not be shown.
@@ -829,6 +829,33 @@ If there is less then `pageSize` rows, pagination will not be shown.
829829
</div>
830830
</div>
831831

832+
### Server-side pagination
833+
834+
To load pages dynamically, simply pass async callback to data:
835+
836+
```ts
837+
async function loadPageData(offset, limit) {
838+
// in real app do await callAdminForthApi or await fetch to get date, use offset and limit value to slice data
839+
return [
840+
{ name: 'John', age: offset, country: 'US' },
841+
{ name: 'Rick', age: offset+1, country: 'CA' },
842+
{ name: 'Alice', age: offset+2, country: 'BR' },
843+
]
844+
}
845+
846+
<Table
847+
:columns="[
848+
{ label: 'Name', fieldName: 'name' },
849+
{ label: 'Age', fieldName: 'age' },
850+
{ label: 'Country', fieldName: 'country' },
851+
]"
852+
//diff-remove
853+
:data="[...]
854+
//diff-add
855+
:data="loadPageData"
856+
857+
:pageSize="3"
858+
```
832859

833860
## ProgressBar
834861

adminforth/spa/src/afcl/Table.vue

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,24 @@
6666
</li>
6767
</ul>
6868
</nav>
69+
<nav v-if="typeof(props.data)==='function'" class="afcl-table-pagination-container bg-lightTableBackground dark:bg-darkTableBackground flex items-center flex-column flex-wrap md:flex-row justify-between p-4"
70+
:aria-label="$t('Table navigation')">
71+
<i18n-t
72+
keypath="Showing page {from}" tag="span" class="afcl-table-pagination-text text-sm font-normal text-lightTablePaginationText dark:text-darkTablePaginationText mb-4 md:mb-0 block w-full md:inline md:w-auto"
73+
>
74+
<template #from><span class="font-semibold text-lightTablePaginationNumeration dark:text-darkTablePaginationNumeration">{{currentPage}}</span></template>
75+
</i18n-t>
76+
<div>
77+
<button
78+
@click="switchPage(Math.max(1, currentPage - 1))"
79+
class="afcl-table-pagination-button rounded-s-lg p-2 ms-0 text-blue-600 bg-lightActivePaginationButtonBackground border border-lightActivePaginationButtonBackground text-lightActivePaginationButtonText dark:bg-darkActivePaginationButtonBackground dark:border-darkActivePaginationButtonBackground dark:text-darkActivePaginationButtonText hover:opacity-90"
80+
> <IconArrowLeftOutline /> </button>
81+
<button
82+
@click="switchPage(currentPage + 1)"
83+
class="afcl-table-pagination-button rounded-e-lg p-2 text-lightUnactivePaginationButtonText border bg-lightUnactivePaginationButtonBackground border-lightUnactivePaginationButtonBorder hover:bg-lightUnactivePaginationButtonHoverBackground hover:text-lightUnactivePaginationButtonHoverText dark:bg-darkUnactivePaginationButtonBackground dark:border-darkUnactivePaginationButtonBorder dark:text-darkUnactivePaginationButtonText dark:hover:bg-darkUnactivePaginationButtonHoverBackground dark:hover:text-darkUnactivePaginationButtonHoverText"
84+
> <IconArrowRightOutline /> </button>
85+
</div>
86+
</nav>
6987
</div>
7088

7189

@@ -74,6 +92,8 @@
7492

7593
<script setup lang="ts">
7694
import { ref, type Ref, computed } from 'vue';
95+
import { asyncComputed } from '@vueuse/core';
96+
import { IconArrowRightOutline, IconArrowLeftOutline } from '@iconify-prerendered/vue-flowbite';
7797
7898
const props = withDefaults(
7999
defineProps<{
@@ -83,7 +103,7 @@
83103
}[],
84104
data: {
85105
[key: string]: any,
86-
}[],
106+
}[] | ((offset: number, limit: number) => Promise<{ [key: string]: any }[]>),
87107
evenHighlights?: boolean,
88108
pageSize?: number,
89109
}>(), {
@@ -95,12 +115,17 @@
95115
const currentPage = ref(1);
96116
97117
const totalPages = computed(() => {
118+
if (typeof props.data === 'function') {};
98119
return Math.ceil(props.data.length / props.pageSize);
99120
});
100121
101-
const dataPage = computed(() => {
122+
const dataPage = asyncComputed( async() => {
102123
const start = (currentPage.value - 1) * props.pageSize;
103124
const end = start + props.pageSize;
125+
if (typeof props.data === 'function') {
126+
const res = await props.data(currentPage.value, props.pageSize);
127+
return res;
128+
}
104129
return props.data.slice(start, end);
105130
});
106131

0 commit comments

Comments
 (0)