-
- Notifications
You must be signed in to change notification settings - Fork 155
Pagination: changing page submits two requests #119
Description
I was about to investigate why tables tend to flicker on page change and set up a very simple table.
My controller:
public function test(Request $request) { $elements = QueryBuilder::for(Something::class) ->defaultSort('name') ->paginate(perPage: request('perPage')??25); return Inertia::render('Something/Test', [ 'elements' => $elements, ])->table(function (InertiaTable $table) { $table ->perPageOptions([25, 50, 100, 200]) ->defaultSort('name') ->column(key: 'name', label: 'Name'); }); } My vue with table:
<script setup> import AppLayout from '@/Test/Layouts/AppLayout.vue'; import { Table } from "@protonemedia/inertiajs-tables-laravel-query-builder"; const props = defineProps({ elements: Object, }); </script> <template> <AppLayout> <Table :resource="elements" /> </AppLayout> </template> By default it shows 25. When I select 50 as perPage, it shows me 50. When I now go to page 2, it triggers two calls, which retrieves data from DB, twice. Once with correct perPage parameter and once without.
- /test?page=2
- /test?page=2&perPage=50&sort=name
After digging a bit in code I found the problem in Table.vue providing function "function visit(url)" to Pagination.vue as onClick handler:
<slot v-if="resourceMeta.total > queryBuilderProps.perPageOptions[0]" name="**visit**" :on-click="onSetPageChange" :has-data="hasData" :meta="resourceMeta" :per-page-options="queryBuilderProps.perPageOptions" :on-per-page-change="onPerPageChange" > <Pagination :on-click="**visit**" :has-data="hasData" :meta="resourceMeta" :per-page-options="queryBuilderProps.perPageOptions" :on-per-page-change="onPerPageChange" /> </slot> As soon as one of the numbers gets clicked, it calls visit, which calls the passed URL. the URL however is a static set of URLs, dot being modified when perPage or any filter gets updated. Instead urls of the following kind are called: https://myserver/test?page=2
In "visit" method, the mnodel is updated: queryBuilderData.value.page = queryBuilderProps.value.page
and this triggers
watch(queryBuilderData, () => { visit(location.pathname + "?" + generateNewQueryString()) }, {deep: true}) which finally calls the second visit with the correct parameters, refreshing the page with correct values.
I am not too deep into this project though, so I open it as an issue and maybe someone finds a better solution. For me to avoid those problems, I created a "CustomizedTable.vue" and added a new method, which is called on page change and which only updates the model, thus calling visit implicitely, once, instead of calling visit also explicitely.
function onSetPageChange(url) {
let pageName= $inertia.page.props.queryBuilderProps[props.name].pageName??'page'; let tmp = url.split('?'); if (tmp.length == 2) { tmp = tmp[1]; } else { tmp = ""; console.log("Expected URL to contain a single ?"); } // Using Proxy class is fastest solution to date // See https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript const params = new Proxy(new URLSearchParams(tmp), { get: (searchParams, prop) => searchParams.get(prop), }); let value = params[pageName]; queryBuilderData.value.cursor = null; queryBuilderData.value.page = value; } I guess there are better ways to do this, I did not want to abuse the label, so maybe the whole data model should be extended. Then I passed this method to Pagination like:
<Pagination :on-click="onSetPageChange" In the end I still ended up with a second call (this time with identical parameters) as visit() changes the parameters which triggers the watch. As the parameters were equal, I just catched it with s stupid if statement in the onSuccess method of visit():
if (queryBuilderData.value.cursor != queryBuilderProps.value.cursor) queryBuilderData.value.cursor = queryBuilderProps.value.cursor if (queryBuilderData.value.page != queryBuilderProps.value.page) queryBuilderData.value.page = queryBuilderProps.value.page This is not very clean code but did the job now and as I spend a LOT of hours today on debugging why my tables behave strangely, I will probably use this workaround unil there is a nicely done fix.
