How to use Laravel paginations, and how to paginate with ajax so your page doesn't reload.


In this guide we will explain how you can use the Laravel pagination with ajax so your webpage doesn't reload when you select a page, or click the next / prev buttons.

What is a pagination (or paginator)?

Pagination is useful when you need your web framework to return a large number of results, usually in a table format. Returning all results at the same time not only won't allow you to have a minimalist page, but more importantly it will put too much load on your database.

What are Laravel paginations?

Laravel contains a paginator which is integrated with their query builder and ORM (database wrapper) which makes pagination a breeze.

Let's say you have a large database table called transactions, with a million entries.

The Laravel paginator allows you to simply call your object like the following. In this case 25 would be the maximum returned per page:

$transactions = DB::table('transactions')->paginate(25);

In your view you might create a table:

<table>
    <thead>
        <th>Amount</th>
        <th>Date</th>
        <th>ID</th.
    </thead>
    <tbody>
        @foreach ($transactions as $transaction)
            <tr>
                <td>{{ $transactions->amount }}</td>
                <td>{{ $transactions->date }}</td>
                <td>{{ $transactions->id }}</td>
            </tr>
        @endforeach
    </tbody>
</table>

... And finally, you would echo the actual pagination html somewhere:

{{ $transactions->links() }}

This works really well out of the box, however every time you go to another page, the entire page will reload - with the GET variable ?page=X triggering which page to load.

Better than this would be to have ajax page transitions so the entire web page does not have to reload.

How to enable AJAX powered page transitions for the Laravel paginator.

As this works well out of the box, we will try to utilize as much existing functionality as possible.


In this tutorial, we will make the following assumptions:

  1. Our table is called transactions, with three fields: id, date and amount.
  2. You have created a controller named TransactionController
  3. This contains a function: public function table()
  4. You've created a view (table.blade.php) and assigned the appropriate routes.
  5. You will create a new view transactions_table_only.

What a normal pagination controller and view would look like:

Controller

public function table()
{
    $transactions = DB::table('transactions')->paginate(25);
    return view("table", compact("transactions"));
}

View

{{ $transactions->links() }}
<table>
    <thead>
        <th>Amount</th>
        <th>Date</th>
        <th>ID</th.
    </thead>
    <tbody>
        @foreach ($transactions as $transaction)
            <tr>
                <td>{{ $transactions->amount }}</td>
                <td>{{ $transactions->date }}</td>
                <td>{{ $transactions->id }}</td>
            </tr>
        @endforeach
    </tbody>
</table>

What we will change:

1. Move your paginate() call to another function

We need to do this as Javascript needs to directly interface with the $transactions object, and only the table html should be regenerated.

Change your controller to:

public function table()
{
    return view("table");
}

// New function for handling AJAX:
public function get_table(Request $request)
{
    $currentPage = $request->page_num;
    // Set the paginator to the current page
    Paginator::currentPageResolver(function() use ($currentPage) {
        return $currentPage;
    });
    $transactions = DB::table('transactions')->paginate(25);
    return view("transactions_table_only", compact("transactions"));
}

Note the Paginator::currentPageResolver call which sets the current page to the variable $page.

2. Remove the html table from the original view, add it to another view

This needs to be done as the table needs to be reloaded via AJAX.

Move the entire <table> ... </table>, and {{ $transactions->links() }} to this file. We've assumed you called it transactions_table_only.blade.php.

3. Override the default pagination behavior with Javascript

Now, in your newly created view you will need to override the default pagination behavior - by stopping the <a href="./?page=x"> tags from working.

You can do this with the following Javascript in transactions_table_only:

<script>
$(function() {
    $(".pagination a").click(function() {
        return call_post_func($(this).attr('href'));
    });
});
function call_post_func(href)
{
    console.log(href);
    post_this(href)
    return false;
}
</script>

4. Add a POST request to deal with the actual AJAX request

Assuming you've called your function post_this, we now have to send our Controller a POST request, and update the HTML.

Add this function within the original view table.blade.php:

<script>
post_this(page_num)
{
    $.post("/ajax/update_transaction_table", {
        "_token": "{{ csrf_token() }}",
        "page_num": page_num
    },
    function(result){
        $("#search_result").html(result)
    })
}

Ensure you've updated your routes file to route the POST request /ajax/update_transaction_table to the controller function get_table().


That's it! Your view should now update via AJAX, without reloading the page.