Skip to content

Commit cfa7731

Browse files
authored
Merge pull request #350 from devforth/AdminForth/813
chore: update pagination logic and data fetching for afcl table
2 parents 5c0d291 + d6ecb36 commit cfa7731

File tree

1 file changed

+60
-19
lines changed

1 file changed

+60
-19
lines changed

adminforth/spa/src/afcl/Table.vue

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,56 @@
116116
</template>
117117

118118
<script setup lang="ts">
119-
import { ref, type Ref, computed, useTemplateRef, watch, nextTick } from 'vue';
120-
import { asyncComputed } from '@vueuse/core';
119+
import { ref, computed, useTemplateRef, watch, shallowRef, toRef } from 'vue';
121120
import SkeleteLoader from '@/components/SkeleteLoader.vue';
122121
122+
type Row = Record<string, unknown>
123+
type LoadFn = (page: number, pageSize: number) => Promise<{ data: Row[]; total: number }>
124+
125+
const isFunc = (v: unknown): v is LoadFn => typeof v === 'function'
126+
127+
function usePagedData(props: {
128+
data: Row[] | LoadFn
129+
pageSize: number
130+
currentPage: number
131+
}) {
132+
const page = ref(props.currentPage)
133+
const pageSize = toRef(props, 'pageSize')
134+
135+
const isLoading = ref(false)
136+
const error = shallowRef<unknown>(null)
137+
const result = shallowRef<{ data: Row[]; total: number }>({ data: [], total: 0 })
138+
139+
let requestId = 0
140+
141+
async function fetchData() {
142+
const id = ++requestId
143+
isLoading.value = true
144+
error.value = null
145+
try {
146+
if (isFunc(props.data)) {
147+
const res = await props.data(page.value, pageSize.value)
148+
if (id !== requestId) return
149+
result.value = res
150+
} else {
151+
const start = (page.value - 1) * pageSize.value
152+
const end = start + pageSize.value
153+
result.value = { data: props.data.slice(start, end), total: props.data.length }
154+
}
155+
} catch (e) {
156+
if (id !== requestId) return
157+
error.value = e
158+
result.value = { data: [], total: 0 }
159+
} finally {
160+
if (id === requestId) isLoading.value = false
161+
}
162+
}
163+
164+
watch([page, pageSize, () => props.data], fetchData, { immediate: true })
165+
166+
return { page, pageSize, isLoading, error, result, refresh: fetchData }
167+
}
168+
123169
const props = withDefaults(
124170
defineProps<{
125171
columns: {
@@ -137,43 +183,34 @@
137183
}
138184
);
139185
140-
const currentPage = ref(1);
141-
const isLoading = ref(false);
186+
const { result: dataResult, isLoading, error, page: currentPage, pageSize, refresh } = usePagedData({
187+
data: props.data,
188+
pageSize: props.pageSize,
189+
currentPage: 1
190+
});
191+
142192
const pageInput = ref('1');
143193
const rowRefs = useTemplateRef<HTMLElement[]>('rowRefs');
144194
const headerRefs = useTemplateRef<HTMLElement[]>('headerRefs');
145195
const rowHeights = ref<number[]>([]);
146196
const columnWidths = ref<number[]>([]);
147197
148-
const dataResult = asyncComputed( async() => {
149-
if (typeof props.data === 'function') {
150-
isLoading.value = true;
151-
const result = await props.data(currentPage.value, props.pageSize);
152-
isLoading.value = false;
153-
return result;
154-
}
155-
const start = (currentPage.value - 1) * props.pageSize;
156-
const end = start + props.pageSize;
157-
return { data: props.data.slice(start, end), total: props.data.length };
158-
});
159-
160198
watch(() => currentPage.value, () => {
161-
// rows are set to null when new records are loading
162199
rowHeights.value = !rowRefs.value ? [] : rowRefs.value.map((el: HTMLElement) => el.offsetHeight);
163200
columnWidths.value = !headerRefs.value ? [] : headerRefs.value.map((el: HTMLElement) => el.offsetWidth);
164201
});
165202
166-
167203
const totalPages = computed(() => {
168204
return dataResult.value?.total ? Math.ceil(dataResult.value.total / props.pageSize) : 1;
169205
});
170206
171-
const dataPage = asyncComputed( async() => {
207+
const dataPage = computed(() => {
172208
return dataResult.value.data;
173209
});
174210
175211
function switchPage(p: number) {
176212
currentPage.value = p;
213+
pageInput.value = p.toString();
177214
}
178215
179216
const emites = defineEmits([
@@ -191,6 +228,10 @@
191228
pageInput.value = validPage.toString();
192229
}
193230
231+
watch(() => currentPage.value, (newPage) => {
232+
pageInput.value = newPage.toString();
233+
});
234+
194235
async function onPageKeydown(event: any) {
195236
// page input should accept only numbers, arrow keys and backspace
196237
if (['Enter', 'Space'].includes(event.code) ||

0 commit comments

Comments
 (0)