grozavule's avatar

Pagination in Laravel 9 using Bootstrap

I'm new to using pagination in Laravel. I'd like to use Bootstrap to handle it for me. The first page displays properly, but it fails on the next page. Here is the code from the controller:

function show(Request $request)
    {
        $validInput = $request->validate([
            'itemName' => 'string|min:5|nullable',
            'status' => 'string|min:5|nullable',
        ]);
        
        $items = IcItem::query()
            ->when(strlen($validInput['itemName']) > 0, function($query) use ($validInput){
                return $query->where('partnum', '=', $validInput['itemName']);
            })
            ->when(strlen($validInput['status']) > 0, function($query) use ($validInput){
                return $query->where('status_flag', '=', $validInput['status']);
            });

        return view('inventory.find.show', ['items' => $items->simplePaginate(10)]);
    }

The code errors out on the first when conditional. It says it can't find $validInput['itemName']. How do I get around this?

0 likes
13 replies
grozavule's avatar

Thanks for the suggestion. I updated the last line of code to the following:

return view('inventory.find.show', ['items' => $items->simplePaginate(10)->withQueryString()]);

The query string didn't append to the URL, and the error still occurs. Was there something else I needed to add to the Blade template?

Sinnbeck's avatar
Sinnbeck
Best Answer
Level 102

Try giving it a fallback

strlen($validInput['itemName'] ?? '') > 0
1 like
grozavule's avatar

@Sinnbeck Does the pagination need to re-run the query for each new page, or does it somehow save and pass the full results of the original query to the controller?

click's avatar

Show us your blade file where you render the pagination.

Please note that even if you pass the correct query parameters your page will still fail if someone manually removes ?itemName= or &status= from the URL. If the values are not mandatory you should also expect them to be empty.

$items = IcItem::query()
  ->when(strlen($validInput['itemName'] ?? '') > 0, function($query) use ($validInput){
    return $query->where('partnum', '=', $validInput['itemName']);
  })
  ->when(strlen($validInput['status'] ?? '') > 0, function($query) use ($validInput){
    return $query->where('status_flag', '=', $validInput['status']);
});
grozavule's avatar

@click Here is the code in the Blade template:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Inventory Find</title>
    @vite(['resources/js/app.js'])
</head>
<body>
<div class="container">
    <table class="table table-striped">
        <thead class="table-dark">
        <tr>
            <th>ITEM NAME</th>
            <th>STATUS</th>
            <th>PART NUMBER</th>
            <th>MANUFACTURER</th>
            <th>MANUFACTURER PART NUMBER</th>
            <th>WEIGHT</th>
        </tr>
        </thead>
        @foreach($items as $item)
            <tr>
                <td>
                    <div class="container">
                        {{ $item->name }}
                    </div>
                    <div class="container">
                        <button type="button" class="btn btn-outline-dark" href="#" onclick="openwin('index.php?act=item_maint&edit=Edit&inq=inq&noheaders=true&editid={{ $item->id }}',800,1000); return false;">INFO</button>
                        <button type="button" class="btn btn-outline-dark" href="#" onclick="openwin('index.php?act=item_maint&edit=Edit&noheaders=true&editid={{ $item->id }}',800,1000); return false;">EDIT</button>
                        <button type="button" class="btn btn-outline-dark" href='#' onclick="openwin('index.php?act=inventory_maint&noheaders=true&param=&editid={{ $item->id }}',800,1000); return false">INV ADJUST</button>
                        <button type="button" class="btn btn-outline-dark" href="#" onclick="openwin('index.php?act=bin_move_R2&customfolder=true&noheaders=true&editid={{ $item->id }}',400,850); return false">BIN MOVE</button>
                        <button type="button" class="btn btn-outline-dark" href="#" onclick="openwin('index.php?act=inventory_store_list_R2&noheaders=true&item={{ $item->id }}',800,1000);">INVENTORY</button>
                    </div>
                </td>
                <td>{{ $item->status_flag }}</td>
                <td>{{ $item->partnum }}</td>
                <td>{{ $item->man }}</td>
                <td>{{ $item->mfrnum }}</td>
                <td>{{ $item->weight }}</td>
            </tr>
        @endforeach
    </table>
    {{ $items->links() }}
</div>
</body>
</html>
click's avatar

@grozavule and what is the url you see behind the pagination that is rendered?

  • If you visit page 1, do you have the two query parameters in your URL?
  • If you see the first page, how do the links to page 2, page 3, look like?
grozavule's avatar

@click Here is the full URL and query string from the first page:

http://sk-dev.opro.prosalesinc.com/inventory/find/show?itemName=&extendedDescription=&partNumber=&oldPartNumber=&bin=&salesOrder=&vendor=&manufacturer=&mfgPartNumber=&vendorPartNumber=&status=Active&inventoryClass=&inventoryRank=&itemCategory=&submit=Search

Here is the full URL and query string from the second page:

http://sk-dev.opro.prosalesinc.com/inventory/find/show?status=Active&submit=Search&page=2
click's avatar

@grozavule If you change your query to:

$items = IcItem::query()
  ->when(strlen($validInput['itemName'] ?? '') > 0, function($query) use ($validInput){
    return $query->where('partnum', '=', $validInput['itemName']);
  })
  ->when(strlen($validInput['status'] ?? '') > 0, function($query) use ($validInput){
    return $query->where('status_flag', '=', $validInput['status']);
});

it should work. As you can see in your links the links are OK because the status query field is visible in the link. Only all of the empty ones are not part of your query string anymore. So by adding ?? '' to your array check your prevent any errors if the key itemName does not exist in your query string.

1 like

Please or to participate in this conversation.