Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

emmatraversy's avatar

Pagination Page Reset By Changing Filters (Is One Character Behind)

Hi everyone I have this Inertia Index Page which is a data table and some filters like search, sort, daterange ... I have a problem with pagination: When user is in page=5 and searches something like "test" because only there is 1 page results available (or no results at all) there is an empty page in page=5$search=test...

So I tried to reset the page in query string when the filters change and its working fine:

export default function Index({ users, filters }) {

  const searchDebounceTimer = useRef(null);
  const [searchTerm, setSearchTerm] = useState(filters.search);
  const [searchField, setSearchField] = useState(filters.searchField);
  const [sortField, setSortField] = useState(filters.sortBy);
  const [sortDirField, setSortDirField] = useState(filters.dir);
  const [dateRange, setDateRange] = useState([
    filters.dateStart,
    filters.dateEnd,
  ]);
  const [dateString, setDateString] = useState(filters.date);

  const searchUsers = () => {
    const queryParams = {
      ...(searchTerm && { search: searchTerm }),
      ...(searchField && { searchField: searchField }),
      ...(sortField && { sortBy: sortField }),
      ...(sortDirField && { dir: sortDirField }),
      ...(dateString && { date: dateString }),
    };

    // Check if any filter other than page has changed
    const filtersChanged = Object.keys(filters).some(
      (key) => key !== 'page' && filters[key] !== queryParams[key]
    );

    // Reset page to 1 if any filter has changed
    const newPage = filtersChanged ? 1 : filters.page;

    if (searchTerm !== null) {
      router.get(
        '/users',
        {
          ...queryParams,
          page: newPage,
        },
        {
          preserveState: true,
          replace: true,
        }
      );
    }
  };

  useEffect(() => {
    clearTimeout(searchDebounceTimer.current);
    searchDebounceTimer.current = setTimeout(searchUsers, 200);
  }, [searchTerm, searchField, sortField, sortDirField, dateString]);
...
...
...

for search I have a problem: Page Reset is one character behind ("test" example) page=5&search=t -> does nothing, i should type second character to make it reset page: page=5&search=te -> page=1&search=te

So search input is one character behind And Other fields should be assigned once before they can do the page reset on change I dont know if its related to them not being defined or something else

I was wondering if its the right strategy or i should figure it out in backend instead of front

I really appreciate your help Regards

0 likes
11 replies
gych's avatar

Does this only happen when you update the searchTerm or also when you update other filters like for example sortField?

emmatraversy's avatar

@gyc I'm sorry for misleading information. I checked it again and unfortunately all inputs are same. I tought its only for search but it seems: when others are not set for the first time, wont affect the page change. they have to be in query present (set one time) so they can reset the page

gych's avatar

@emmatraversy No problem :) Can you share you back end controller method that handles the search ?

emmatraversy's avatar

@gych yeah, ofcourse: I haven't code the date range filter yet.

<?php

namespace App\Http\Controllers\TestingHub;

use Inertia\Inertia;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Request;


use App\Models\User;

class UserController extends Controller
{
    public function index()
    {
        $searchFields = ['name', 'email'];
        $searchField = in_array(Request::input('searchField'), $searchFields) ? Request::input('searchField') : $searchFields[0];
        
        // Parse sort parameter
        $sortFields = ['name', 'email'];
        $sortField = in_array(Request::input('sortBy'), $sortFields) ? Request::input('sortBy') : null;
        $sortDirection = in_array(Request::input('dir', 'asc'), ['asc','desc']) ? Request::input('dir', 'asc') : 'asc';

        /** @disregard P1013 method exists but intelephense cant see it */
        $users = User::query()
            ->when(Request::input('search'), function ($query, $search) use ($searchField) {
                $query->where($searchField, 'like', "%{$search}%");
            })
            ->when($sortField, function ($query, $sortField) use ($sortDirection) {
                $query->orderBy($sortField, $sortDirection);
            })
            ->paginate(10)->withQueryString();
    
        $filters = Request::only(['page','search','searchField','sortBy','dir','date']);
        return Inertia::render('Users/Index', [
            'users' => $users,
            'filters' => $filters,
        ]);
    }
}

``

emmatraversy's avatar

@gych yeah, ofcourse: I haven't code the date range filter yet.

<?php

namespace App\Http\Controllers\TestingHub;

use Inertia\Inertia;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Request;


use App\Models\User;

class UserController extends Controller
{
    public function index()
    {
        $searchFields = ['name', 'email'];
        $searchField = in_array(Request::input('searchField'), $searchFields) ? Request::input('searchField') : $searchFields[0];
        
        // Parse sort parameter
        $sortFields = ['name', 'email'];
        $sortField = in_array(Request::input('sortBy'), $sortFields) ? Request::input('sortBy') : null;
        $sortDirection = in_array(Request::input('dir', 'asc'), ['asc','desc']) ? Request::input('dir', 'asc') : 'asc';

        /** @disregard P1013 method exists but intelephense cant see it */
        $users = User::query()
            ->when(Request::input('search'), function ($query, $search) use ($searchField) {
                $query->where($searchField, 'like', "%{$search}%");
            })
            ->when($sortField, function ($query, $sortField) use ($sortDirection) {
                $query->orderBy($sortField, $sortDirection);
            })
            ->paginate(10)->withQueryString();
    
        $filters = Request::only(['page','search','searchField','sortBy','dir','date']);
        return Inertia::render('Users/Index', [
            'users' => $users,
            'filters' => $filters,
        ]);
    }
}

``

shariff's avatar

Did you try appending query params?

->paginate(10)->appends(request()->query());
emmatraversy's avatar

@shariff Thank you for your reply I suppose ->withQueryString(); do the same thing.

Unfortunetly problem is on the frontend part I guess. When it can't detect a filter change when it is not assigned once.

1 like
emmatraversy's avatar

@gych The problem is here: I put the console logs

    const filtersChanged = Object.keys(filters).some(
      (key) => {
        console.log(`Checking filter ${key}`);
        const filterChanged = key !== 'page' && (
          !queryParams.hasOwnProperty(key) || // Filter doesn't exist in queryParams
          filters[key] !== queryParams[key] // Filter value has changed
        );
        console.log(`Filter ${key} changed: ${filterChanged}`);
        return filterChanged;
      }
    );

it only checks "page" filter not other keys because they don't exist yet there is nothing for him to check

and also checking filters seem a little wrong since its assigned serverside. I think I should do something in that useEffect (or search function) but rely on other thing than filters because filter will set after the router request, I dont know how to explain my tought sorry

gych's avatar
gych
Best Answer
Level 29

@emmatraversy I personally always use ->appends() with a different approach which doesn't require me to reset the page in the front end.

Add this to set which page to use in the pagination, if there's not page in the request use 1 as default.

$page = $request->page ?? 1;

Then with paginate use this

->paginate(10, ['*'], 'page', $page)->appends(['search', 'searchField', 'sortBy', 'dir', 'date']);
emmatraversy's avatar

@gych Thank you for your reply. Sorry for the delay. I had an unexpected health issue arise a couple of weeks ago that required me to be hospitalized for a few days.

Thanks for your kind replies and help. It seems this approach will fix my problem, I'll give that a shot then.

Best Regards

Please or to participate in this conversation.