|
91 | 91 | <template #total><span class="font-semibold text-lightTablePaginationNumeration dark:text-darkTablePaginationNumeration">{{ dataResult.total }}</span></template> |
92 | 92 | </i18n-t> |
93 | 93 | <div class="af-pagination-container flex flex-row items-center xs:flex-row xs:justify-between xs:items-center gap-3"> |
94 | | - <div class="inline-flex" :class="isLoading || props.isLoading ? 'pointer-events-none select-none opacity-50' : ''"> |
| 94 | + <div class="inline-flex" :class="blockPagination ? 'pointer-events-none select-none opacity-50' : ''"> |
95 | 95 | <!-- Buttons --> |
96 | 96 | <button |
97 | 97 | class="flex items-center py-1 px-3 gap-1 text-sm font-medium text-lightActivePaginationButtonText bg-lightActivePaginationButtonBackground border-r-0 rounded-s hover:opacity-90 dark:bg-darkActivePaginationButtonBackground dark:text-darkActivePaginationButtonText disabled:opacity-50" |
98 | 98 | @click="currentPage--; pageInput = currentPage.toString();" |
99 | | - :disabled="currentPage <= 1 || isLoading || props.isLoading"> |
| 99 | + :disabled="currentPage <= 1 || blockPagination"> |
100 | 100 | <svg class="w-3.5 h-3.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" |
101 | 101 | viewBox="0 0 14 10"> |
102 | 102 | <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" |
|
106 | 106 | <button |
107 | 107 | class="flex items-center py-1 px-3 text-sm font-medium text-lightUnactivePaginationButtonText focus:outline-none bg-lightUnactivePaginationButtonBackground border-r-0 border border-lightUnactivePaginationButtonBorder hover:bg-lightUnactivePaginationButtonHoverBackground hover:text-lightUnactivePaginationButtonHoverText dark:bg-darkUnactivePaginationButtonBackground dark:text-darkUnactivePaginationButtonText dark:border-darkUnactivePaginationButtonBorder dark:hover:text-darkUnactivePaginationButtonHoverText dark:hover:bg-darkUnactivePaginationButtonHoverBackground disabled:opacity-50" |
108 | 108 | @click="switchPage(1); pageInput = currentPage.toString();" |
109 | | - :disabled="currentPage <= 1 || isLoading || props.isLoading"> |
| 109 | + :disabled="currentPage <= 1 || blockPagination"> |
110 | 110 | <!-- <IconChevronDoubleLeftOutline class="w-4 h-4" /> --> |
111 | 111 | 1 |
112 | 112 | </button> |
|
123 | 123 | <button |
124 | 124 | class="flex items-center py-1 px-3 text-sm font-medium text-lightUnactivePaginationButtonText focus:outline-none bg-lightUnactivePaginationButtonBackground border-l-0 border border-lightUnactivePaginationButtonBorder hover:bg-lightUnactivePaginationButtonHoverBackground hover:text-lightUnactivePaginationButtonHoverText dark:bg-darkUnactivePaginationButtonBackground dark:text-darkUnactivePaginationButtonText dark:border-darkUnactivePaginationButtonBorder dark:hover:text-darkUnactivePaginationButtonHoverText dark:hover:bg-darkUnactivePaginationButtonHoverBackground disabled:opacity-50" |
125 | 125 | @click="currentPage = totalPages; pageInput = currentPage.toString();" |
126 | | - :disabled="currentPage >= totalPages || isLoading || props.isLoading" |
| 126 | + :disabled="currentPage >= totalPages || blockPagination" |
127 | 127 | > |
128 | 128 | {{ totalPages }} |
129 | 129 |
|
130 | 130 | </button> |
131 | 131 | <button |
132 | 132 | class="flex items-center py-1 px-3 gap-1 text-sm font-medium text-lightActivePaginationButtonText focus:outline-none bg-lightActivePaginationButtonBackground border-l-0 rounded-e hover:opacity-90 dark:bg-darkActivePaginationButtonBackground dark:text-darkActivePaginationButtonText disabled:opacity-50" |
133 | 133 | @click="currentPage++; pageInput = currentPage.toString();" |
134 | | - :disabled="currentPage >= totalPages || isLoading || props.isLoading" |
| 134 | + :disabled="currentPage >= totalPages || blockPagination" |
135 | 135 | > |
136 | 136 | <svg class="w-3.5 h-3.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" |
137 | 137 | viewBox="0 0 14 10"> |
|
163 | 163 | }[], |
164 | 164 | data: { |
165 | 165 | [key: string]: any, |
166 | | - }[] | ((params: { offset: number, limit: number, sortField?: string, sortDirection?: 'asc' | 'desc' }) => Promise<{data: {[key: string]: any}[], total: number}>), |
| 166 | + }[] | ((params: { offset: number, limit: number, sortField?: string, sortDirection?: 'asc' | 'desc' }, abortSignal?: AbortSignal) => Promise<{data: {[key: string]: any}[], total: number}>), |
167 | 167 | evenHighlights?: boolean, |
168 | 168 | pageSize?: number, |
169 | 169 | isLoading?: boolean, |
170 | 170 | defaultSortField?: string, |
171 | 171 | defaultSortDirection?: 'asc' | 'desc', |
172 | 172 | makeHeaderSticky?: boolean, |
173 | 173 | makePaginationSticky?: boolean, |
| 174 | + blockPaginationOnLoading?: boolean, |
174 | 175 | }>(), { |
175 | 176 | evenHighlights: true, |
176 | 177 | pageSize: 5, |
| 178 | + blockPaginationOnLoading: true, |
177 | 179 | } |
178 | 180 | ); |
179 | 181 |
|
|
188 | 190 | const isAtLeastOneLoading = ref<boolean[]>([false]); |
189 | 191 | const currentSortField = ref<string | undefined>(props.defaultSortField); |
190 | 192 | const currentSortDirection = ref<'asc' | 'desc'>(props.defaultSortDirection ?? 'asc'); |
| 193 | + const oldAbortController = ref<AbortController | null>(null); |
| 194 | +
|
| 195 | + const blockPagination = computed(() => (isLoading.value || props.isLoading) && props.blockPaginationOnLoading); |
191 | 196 |
|
192 | 197 | onMounted(() => { |
193 | 198 | // If defaultSortField points to a non-sortable column, ignore it |
|
277 | 282 | isLoading.value = true; |
278 | 283 | const currentLoadingIndex = currentPage.value; |
279 | 284 | isAtLeastOneLoading.value[currentLoadingIndex] = true; |
280 | | - const result = await props.data({ |
281 | | - offset: (currentLoadingIndex - 1) * props.pageSize, |
282 | | - limit: props.pageSize, |
283 | | - sortField: currentSortField.value, |
284 | | - ...(currentSortField.value ? { sortDirection: currentSortDirection.value } : {}), |
285 | | - }); |
| 285 | + const abortController = new AbortController(); |
| 286 | + if (oldAbortController.value) { |
| 287 | + oldAbortController.value.abort(); |
| 288 | + } |
| 289 | + oldAbortController.value = abortController; |
| 290 | + const result = await props.data( |
| 291 | + { |
| 292 | + offset: (currentLoadingIndex - 1) * props.pageSize, |
| 293 | + limit: props.pageSize, |
| 294 | + sortField: currentSortField.value, |
| 295 | + ...(currentSortField.value ? { sortDirection: currentSortDirection.value } : {}), |
| 296 | + }, |
| 297 | + abortController.signal |
| 298 | + ); |
286 | 299 | isAtLeastOneLoading.value[currentLoadingIndex] = false; |
287 | 300 | if (isAtLeastOneLoading.value.every(v => v === false)) { |
288 | 301 | isLoading.value = false; |
289 | 302 | } |
| 303 | + if(abortController.signal.aborted) return; |
290 | 304 | dataResult.value = result; |
291 | 305 | } else if (typeof props.data === 'object' && Array.isArray(props.data)) { |
292 | 306 | const start = (currentPage.value - 1) * props.pageSize; |
|
0 commit comments