A Tutorial on custom pagination templates with links and stats in Laravel 5.3

in Laravel/PHP/Tutorials & Samples/Web Development

For a recent project, I had to setup basic pagination with Laravel 5.3. Coming form the CakePHP world, it was pretty straightforward and luckily I landed on an awesome blog post by Matt Cutts on pagination in Laravel 5.3. Using most of what I learned from that article, I was able to get pagination up and running. But one thing that he does not cover was how to get the pretty stats like you see on most professional websites. You know, the stats that say: showing 1 to 10 of 235 entries. So, this quick tutorial will show you how to get the the pagination stats along with the pagination links. As always, I like to give a quick picture of what we will be building, so here is the picture below:

Step 1: Setup the boring stuff (controller and view)

As you can see from the screenshot above, I have a collection of quotes. But it could be a collection of anything. The mechanism for pagination is pretty much the same. In this case, I will assume that we have an index function in our controller that loads all the quotes in a papinated format. Here is what the code should look like:

<?php

namespace App\Http\Controllers;

use App\Models\Quote;
use App\Http\Controllers\Controller;

class QuotesController extends Controller
{
    /**
     * Show all of the quotes for the application.
     *
     * @return Response
     */
    public function index()
    {
        $quotes = Quote::paginate(10);

        return view('quote.index', ['quotes' => $quotes]);
    }
}

In the code above, we are getting all the quotes from our database and paginating them, 10 pages at a time. We are also telling the application to return the index.blade.php file which contains the view for how to display the quotes. Our index.blade.php for quotes would then have the following contents:

// resource/views/quotes/index.blade.php
@foreach ($quotes as $quote)
    <!-- display the quote however you like -->
@endforeach

Once this done, now comes the pagination magic.

Step 2: Do the Pagination Magic

As Matt explains so much better than I can:

By default, the paginate() method on your Eloquent objects reads the query parameters of your request and detects which page you’re on. So in this example, it’ll read the ?page query parameter and grab 10 records for that page. It’ll pass those 10 in, and when we foreach on the $quotess variable, we’ll just be looping over those 10. But if you retrieve those 10 records using paginate() instead of something like all(), you get a new method available on your $quotes object (or other Eloquent result) named links(), and this method returns the view string appropriate for showing a list of pagination buttons

So, we can modify our index.blade.php file so that we now use the links() call.

// resource/views/quotes/index.blade.php
@foreach ($quotes as $quote)
    <!-- display the quote however you like -->
@endforeach
{{ $tasks->links() }}

Doing this will trigger Laravel to use the default pagination view that comes with Laravel. This view is based on Bootstrap, like most other views in Laravel. By default, the template that is rendering this can be found in the Illuminate\Pagination component: resources/views/bootstrap-3.blade.php. This is what it looks like right now:

<ul class="pagination">
    <!-- Previous Page Link -->
    @if ($paginator->onFirstPage())
        <li class="disabled"><span>&laquo;</span></li>
    @else
        <li><a href="{{ $paginator->previousPageUrl() }}" rel="prev">&laquo;</a></li>
    @endif

    <!-- Pagination Elements -->
    @foreach ($elements as $element)
        <!-- "Three Dots" Separator -->
        @if (is_string($element))
            <li class="disabled"><span>{{ $element }}</span></li>
        @endif

        <!-- Array Of Links -->
        @if (is_array($element))
            @foreach ($element as $page => $url)
                @if ($page == $paginator->currentPage())
                    <li class="active"><span>{{ $page }}</span></li>
                @else
                    <li><a href="{{ $url }}">{{ $page }}</a></li>
                @endif
            @endforeach
        @endif
    @endforeach

    <!-- Next Page Link -->
    @if ($paginator->hasMorePages())
        <li><a href="{{ $paginator->nextPageUrl() }}" rel="next">&raquo;</a></li>
    @else
        <li class="disabled"><span>&raquo;</span></li>
    @endif
</ul>

Since this is part of the Laravel core components, we will not modify this file. Remember: Rule number one of Laravel club is that you don’t modify the core components. Instead, I create a new directory in views called pagination. Inside this directory, I place 2 files:

  • pagination_links.blade.php: which will contain the pagination links
  • pagination_stats.blade.php: which will contain the pagination stats

The contents of pagination_links.blade.php are pretty boring since it is an exact copy of what was in the core view for pagination. The only thing that I add is the check to make sure that there is a pagination object to draw or not

// resource/views/pagination/pagination_links.blade.php
@if ($paginator->hasPages())
    <ul class="pagination">
        <!-- Previous Page Link -->
        @if ($paginator->onFirstPage())
            <li class="disabled"><span><i class="fa fa-angle-double-left"></i> Previous</span></li>
        @else
            <li><a href="{{ $paginator->previousPageUrl() }}" rel="prev"><i class="fa fa-angle-double-left"></i> Previous</a></li>
        @endif

        <!-- Pagination Elements -->
		@foreach ($elements as $element)
			<!-- "Three Dots" Separator -->
			@if (is_string($element))
			<li class="disabled"><span>{{ $element }}</span></li>
			@endif

			<!-- Array Of Links -->
			@if (is_array($element))
				@foreach ($element as $page => $url)
					@if ($page == $paginator->currentPage())
						<li class="active"><span>{{ $page }}</span></li>
					@else
						<li><a href="{{ $url }}">{{ $page }}</a></li>
					@endif
				@endforeach
			@endif
		@endforeach

		<!-- Next Page Link -->
		@if ($paginator->hasMorePages())
			<li><a href="{{ $paginator->nextPageUrl() }}" rel="next">Next <i class="fa fa-angle-double-right"></i></a></li>
		@else
			<li class="disabled"><span>Next <i class="fa fa-angle-double-right"></i></span></li>
		@endif
    </ul>
@endif

The contents of pagination_stats is a bit more interesting because this is where I actually display the page statistics and this is something that does not come with Laravel by default. Here is the contents of the file:

// resource/views/pagination/pagination_links.blade.php
@if ($paginator->hasPages())
    Showing <strong>{{ ((($paginator->currentPage() -1) * $paginator->perPage()) + 1) }}</strong> to <strong>{{ ((($paginator->currentPage() -1) * $paginator->perPage()) + $paginator->count()) }}</strong> of <strong>{{ $paginator->total() }}</strong> entries. page <strong>{{ $paginator->currentPage() }}</strong> /<strong>{{ $paginator->lastPage() }}</strong>
@endif

The stats contain some basic math to determine the item numbers using 3 variables:

  • the current page number
  • the number of items on the current page
  • the number of items to be loaded per page

Now that both templates have been written, its time to use them in our index.blade.php file. It’s actually pretty simple since the links() method allows you to pass a view as a parameter and the stats are independent of the links. So the index file now looks like so:

// resource/views/quotes/index.blade.php
@foreach ($quotes as $quote)
    <!-- display the quote however you like -->
@endforeach
// display pagination stats:
@include('pagination.pagination_stats', ['paginator' => $quotes])
// display pagination links:
{{ $tasks->links('pagination.pagination_links') }}

And voila! you have your custom pagination links with stats in Laravel that you can customize however you like.

Step 3: More boring stuff (additional info)

The paginator in Laravel comes with a bunch of useful features. You can find out more about it throug the official documentation of Laravel. You should also be aware of the helper methods that come with the paginator. Here they are below:

Method Name Description
$paginator->count() Returns number of records for current page
$paginator->currentPage() Returns the current page number
$paginator->hasMorePages() Checks whether there are more pages
$paginator->nextPageUrl() Returns the full url of next page
$paginator->perPage() Returns how many records will show per page
$paginator->previousPageUrl() Returns the full url of previous page
$paginator->url($page) Returns the url for given page number
$paginator->lastPage() Returns the last page number
(In simplePaginate this method does not exist)
$paginator->total() Returns the total number of items being paginated
(In simplePaginate this method does not exist)
Tags:

Mifty Yusuf is a Montreal-based software developer who enjoys playing with new web technologies as well as comic books and illustrations. He beleives that, no matter what the question is, the answer is always Batman!

1 Comment

Leave a Reply

Your email address will not be published.

*

Latest from Laravel

Go to Top