With infinite page scroll new content loads dynamically while scrolling the page until content is available.
It is user-friendly and improves page load time.
In this tutorial, I show how you can load MySQL database content on page scroll using jQuery AJAX in the Laravel 9 project.
Contents
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.
php artisan make:migration create_posts_table
- Now, navigate to
database/migrations/
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('content'); $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, content, and link using the
$fillable
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','content','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 inposts
table to$data['totalrecords']
, and fetch first 4 records fromposts
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']; $content = $record['content']; $link = $record['link']; $html .= '<div class="card w-75 post"> <div class="card-body"> <h5 class="card-title">'.$title.'</h5> <p class="card-text">'.$content.'</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 –
- start – Store current row position.
- rowperpage – Store the number of rows to fetch at a time.
- totalrecords – Store the total number of records.
Script –
Create 3 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()
.
- onScroll() – Using this function check if the scroll reaches the bottom of the page or not. If reached then call
fetchData()
.
Define scroll
event on window
and also define touchmove
event on document
for mobile devices. From both events call onScroll()
.
Completed Code
<!DOCTYPE html> <html> <head> <title>How to Load content on page scroll in Laravel 9</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/bootstrap@5.1.0/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']; $content = $post['content']; $link = $post['link']; @endphp <div class="card w-75 post"> <div class="card-body"> <h5 class="card-title">{{ $title }}</h5> <p class="card-text">{{ $content }}</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(){ onScroll(); }); </script> </body> </html>
7. Demo
8. Conclusion
The code works even if the page doesn’t have enough content to scroll on the page first time load.
If the content is not loading on the page scroll then debug it using the browser network tab.
If you found this tutorial helpful then don't forget to share.