How to Load content on page scroll in Laravel 8

With infinite page scroll new content loads dynamically while scrolling the page.

It is user-friendly and improves page speed.

In this tutorial, I show how you can load MySQL database content on page scroll using jQuery AJAX in Laravel 8 project.

How to Load content on page scroll in Laravel 8


Contents

  1. Database Configuration
  2. Create Table
  3. Model
  4. Route
  5. Controller
  6. View
  7. Demo
  8. Conclusion

1. Database Configuration

Open .env file.

Specify the host, database name, username, and password.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=tutorial
DB_USERNAME=root
DB_PASSWORD=

2. Create Table

  • Create a new table posts using migration and add some records.
php artisan make:migration create_posts_table
  • Now, navigate to database/migration/ folder from the project root.
  • Find a PHP file that ends with create_posts_table and open it.
  • Define the table structure in the up() method.
public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->text('description');
        $table->string('link');
        $table->timestamps();
    });
}
  • Run the migration –
php artisan migrate
  • The table is been created and add some records in it.

3. Model

  • Create Posts Model.
php artisan make:model Posts
  • Open app/Models/Posts.php file.
  • Specify mass assignable Model attributes – title, description, and link using the $filliable property.

Completed Code

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Posts extends Model
{
    use HasFactory;

    protected $fillable = [
       'title','description','link'
    ];
}

4. Route

  • Open routes/web.php file.
  • Define 2 routes –
    • / – Load index view.
    • /getPosts – This is used to handle AJAX request on page scroll.
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostsController;

Route::get('/', [PostsController::class, 'index']); 
Route::get('/getPosts', [PostsController::class, 'getPosts'])->name('getPosts');

5. Controller

  • Create PostsController Controller.
php artisan make:controller PostsController
  • Open app/Http/Controllers/PostsController.php file.
  • Import Posts Model.

Create $rowperpage class variable to store the number of records fetch at a time. I set it to 4 you can change it according to requirement.

Create 2 methods –

  • index() – Assign $rowperpage to $data['rowperpage'], total number of records in posts table to $data['totalrecords'], and fetch first 4 records from posts table and assign to $data['posts'].

Load index view and pass $data Array.

  • getPosts() – This method is use to handle AJAX request.

Read 'start' from GET request and assign to $start. Fetch records from posts table according to $start and $rowperpage.

Loop on fetched records and create layout and assign to $html variable.

Assign $html to $data['html'].

Return $data Array in JSON format.

Completed Code

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Posts;

class PostsController extends Controller {
       public $rowperpage = 4; // Number of rowsperpage

       public function index(){

            // Number of rowsperpage
            $data['rowperpage'] = $this->rowperpage;

            // Total number of records
            $data['totalrecords'] = Posts::select('*')->count();

            // Fetch 4 records
            $data['posts'] = Posts::select('*') 
                   ->skip(0)
                   ->take($this->rowperpage)
                   ->get();

            // Load index view
            return view('index',$data);
       }

       // Fetch records
       public function getPosts(Request $request){

            $start = $request->get("start");

            // Fetch records
            $records = Posts::select('*') 
                  ->skip($start)
                  ->take($this->rowperpage)
                  ->get();

             $html = "";
             foreach($records as $record){
                  $id = $record['id'];
                  $title = $record['title'];
                  $description = $record['description'];
                  $link = $record['link'];

                  $html .= '<div class="card w-75 post">
                        <div class="card-body">
                             <h5 class="card-title">'.$title.'</h5>
                             <p class="card-text">'.$description.'</p>
                             <a href="'.$link.'" target="_blank" class="btn btn-primary">Read More</a>
                        </div>
                   </div>';
              }

              $data['html'] = $html;

              return response()->json($data);

       }
}

6. View

Create index.blade.php file in resources/views/ folder.

Loop on $posts Array and create layout.

Create 3 hidden fields –

  1. start – Store current row position.
  2. rowperpage – Store the number of rows to fetch at a time.
  3. totalrecords – Store the total number of records.

Script –

Create 2 functions –

  • checkWindowSize() – Using this function to check if the screen is too large or the page has not had enough content to scroll. If the condition is true then fetch new records by calling fetchData() function.
  • fetchData() – Read values from hidden fields. Fetch new records if start <= allcount.

Send AJAX request to route('getPosts'), send start as data, set dataType to ‘json’, and on successful callback append new fetched data response.html after last <div class='post '>. Again check window size by calling checkWindowSize().

scroll event – Check if scroll reaches the bottom of the page or not. If reached then call fetchData().

For mobile defined touchmove event to detect scrolling.

Completed Code

<!DOCTYPE html>
<html>
<head>
       <title>How to Load content on page scroll in Laravel 8</title>

       <!-- Meta -->
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
       <meta charset="utf-8">

       <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">

       <style type="text/css">
       .card{
             margin: 0 auto;
             margin-top: 35px;
       }
       </style>
</head>
<body>

       <div class='container'>

            @foreach($posts as $post)
                 @php
                 $id = $post['id'];
                 $title = $post['title'];
                 $description = $post['description'];
                 $link = $post['link'];
                 @endphp
                 <div class="card w-75 post">
                      <div class="card-body">
                           <h5 class="card-title">{{ $title }}</h5>
                           <p class="card-text">{{ $description }}</p>
                           <a href="{{ $link }}" target="_blank" class="btn btn-primary">Read More</a>
                      </div>
                 </div>
            @endforeach

             <input type="hidden" id="start" value="0">
             <input type="hidden" id="rowperpage" value="{{ $rowperpage }}">
             <input type="hidden" id="totalrecords" value="{{ $totalrecords; }}">

       </div>

       <!-- Script -->
       <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
       <script type="text/javascript">

       checkWindowSize();

       // Check if the page has enough content or not. If not then fetch records
       function checkWindowSize(){
            if($(window).height() >= $(document).height()){
                  // Fetch records
                  fetchData();
            }
       }

       // Fetch records
       function fetchData(){
             var start = Number($('#start').val());
             var allcount = Number($('#totalrecords').val());
             var rowperpage = Number($('#rowperpage').val());
             start = start + rowperpage;

             if(start <= allcount){
                  $('#start').val(start);

                  $.ajax({
                       url:"{{route('getPosts')}}",
                       data: {start:start},
                       dataType: 'json',
                       success: function(response){

                            // Add
                            $(".post:last").after(response.html).show().fadeIn("slow");

                            // Check if the page has enough content or not. If not then fetch records
                            checkWindowSize();
                       }
                  });
             }
       }

       $(document).on('touchmove', onScroll); // for mobile
       
       function onScroll(){

             if($(window).scrollTop() > $(document).height() - $(window).height()-100) {

                   fetchData(); 
             }
       }

       $(window).scroll(function(){

             var position = $(window).scrollTop();
             var bottom = $(document).height() - $(window).height();

             if( position == bottom ){
                   fetchData(); 
             }

        });

        </script>
</body>
</html>

7. Demo

View Demo


8. Conclusion

The code works even if the page doesn’t have enough content to scroll on the page first time load.

If you found this tutorial helpful then don't forget to share.

Leave a Comment