How to Implement Laravel Livewire Load More Pagination

Let's learn how to implement a simple "load more" pagination in Laravel Livewire. By making use of Livewire the data will be dynamic and retrieving new data won't require a page refresh which will make the process more seamless. The steps are very simple to follow so let's get started.

Step 1: Install Dependency

Let's start by installing the dependency and you will need to have "Laravel Livewire" and "TailwindCSS" for this.

composer require livewire/livewire

Once livewire is installed then you can add the necessary "style" and "scripts" tags in your layouts file.

<html>
<head>
    <!-- your other head code here -->
    @livewireStyles
</head>
<body>
    <!-- your other html code here -->

    @livewireScripts
</body>
</html>

For the TailwindCSS you can make use of the available CDN.

<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">

Full Layout Code

The full layout code should be like the below, do note that Laravel Livewire is making use of the "{{ $slot }}" variable instead of the "@yield("content")" variable to render the data.

// views/layouts/app.blade.php

<!DOCTYPE html>
<html class="h-full">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laravel App</title>
    <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
    @livewireStyles
</head>
<body class="font-sans antialiased bg-gray-50 h-full">

    <main class="mt-12 min-h-full">
        {{ $slot }}
    </main>

    @livewireScripts
</body>
</html>

Since the "load more pagination" can be used for any type of resource (users, posts, categories and etc) for this scenario we'll be using "posts" as the main example.

Step 2: Create a new post listing Livewire Component

Now that you have the layout code ready in place, it's time to create a new post listing Livewire component and you can use the command line to generate it.

php artisan livewire:make PostListing

Upon successfully creating the component you should see the message like below

COMPONENT CREATED  ?

CLASS: app/Http/Livewire/PostListing.php
VIEW:  resources/views/livewire/post-listing.blade.php
 

Step 3: Define the Route Endpoints

Before we start with the component logic, define the route in "routes/web.php" to provide the access endpoint.

# routes/web.php

Route::get('/posts', App\Http\Livewire\PostListing::class)
    ->name('posts.listing');

Step 4: PostListing Livewire Component Logic

For the Livewire component, you'll need to make use of the mount() lifecycle method to initialize the data necessary as well as loadPosts() method to load more posts and finally render() method to render the view.

public function mount() {}

public function loadPosts() {}

public function render() {}

For the properties, you need to define "posts", "pageNumber" and "hasMorePages" and this is essential to hold the data and determine the current page number and availability.

public $posts;

public $pageNumber = 1;

public $hasMorePages;

The full code example will be as follows. Do note that Laravel Livewire only accepts PHP "scalar types", Laravel model, and Laravel Collection so other than those types the component will throw an error.

// app/Http/Livewire/PostListing.php

<?php

namespace App\Http\Livewire;

use App\Models\Post;
use Illuminate\Support\Collection;
use Livewire\Component;

class PostListing extends Component
{
    public $posts;

    public $pageNumber = 1;

    public $hasMorePages;

    public function mount()
    {
        $this->posts = new Collection();

        $this->loadPosts();
    }

    public function loadPosts()
    {
        $posts = Post::paginate(12, ['*'], 'page', $this->pageNumber);

        $this->pageNumber += 1;

        $this->hasMorePages = $posts->hasMorePages();

        $this->posts->push(...$posts->items());
    }

    public function render()
    {
        return view('livewire.post-listing')->layout('layouts.app');
    }
}

So a little bit explanation of the code above, there are 5 important flows that you have to know.

  1. When the component load, it will trigger the mount() method, and the "posts" property is initialized with an empty Laravel Collection.

  2. The loadPosts() method is triggered to load the "posts" that are being retrieved from the DB through "Post" model.

  3. The pagination will be determined by the "pageNumber" property.

  4. The retrieved data is "pushed" to the collection.

  5. The "render()" method renders the view.

Step 5: PostListing Views

The views will loop through the "posts" properties and for this example, simple styling is applied with "TailwindCSS" classes. Assuming the "Post" model has a "title" and "body" column, you can access it as you normally would in Laravel Blade file.

<div class="container p-4 mx-auto">
    <h1 class="font-semibold text-2xl font-bold text-gray-800">All Posts</h1>

    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mt-4">
        @foreach($posts as $post)
            <a href="#" class="block p-4 bg-white rounded shadow-sm hover:shadow overflow-hidden">
                <h2 class="truncate font-semibold text-lg text-gray-800">
                    {{ $post['title'] }}
                </h2>

                <p class="mt-2 text-gray-800">
                    {{ $post['body'] }}
                </p>
            </a>
        @endforeach
    </div>

    @if ($hasMorePages)
        <div class="flex items-center justify-center mt-4">
            <button
                class="px-4 py-3 text-lg font-semibold text-white rounded-xl bg-green-500 hover:bg-green-400"
                wire:click="loadPosts"
            >
                Load More
            </button>
        </div>
    @endif
</div>

And finally, after you have looped the "posts" variable, you can place a "Load More" button that has wire:click event to trigger loadPost() method.

Now when you press the "Load More" button, the component will retrieve 12 more posts and the page will be dynamically updated without refreshing the page.

Feel free to leave a comment to ask any questions you might have.