Data Table Pagination with Live Search using Laravel, jQuery, and Ajax Request

In this tutorial, you can learn to create a Live Search Box feature in Laravel 10 Data with Pagination. The tutorial aims to provide students and beginners with a reference for learning to create a useful feature or component of a Laravel Project. Here, I will be providing a simple web application script that demonstrates the creation of the said feature using the Laravel version 10 Framework.

What is Live Search Box?

A Live Search Box is one of the often implemented features or web features in websites or web applications. This is usually used to easily filter the specific data that matches the entered keyword on the search box input. This feature works dynamically without leaving the current page or reloading the pages which means that the new data will be automatically updated without reloading the page assets and other elements.

How to Create a Live Search Box?

There are plenty of ways to achieve the Live Search Box for the paginated data in Laravel Projects. Most of these ways are through HTTP Request. Using jQuery's Ajax Request we can achieve this kind of feature or component. We can simply initiate the Request through Ajax when there are changes made to the search box input. After the Ajax Request has been fulfilled, we can update the data with the updated ones. Check out the source code scripts I have provided below to understand it more.

Sample Scripts

The scripts below are the modified file script of my previously published Laravel Project which is the "Laravel 10: Paginate DB Table Data with Bootstrap Tutorial". Kindly click the provided link (my previously published tutorial title) if you want to learn from scratch.

The modified script result in a simple Laravel Project web page that contains a table that displays the list of members data from the database with the Pagination Feature. Using the scripts, the project will have a search box input on the front end and when the user updates the search input value, the search process will be executed and updates the table data with the members data that contains information that matches the given keyword. Here, the live search feature has the ability to preserve the searched keyword whereas the entered keyword will stay on the search input field and the searched data will remain even if the user forcibly reloads or refresh the page.

Page View File Script

The modified file is known as members.blade.php. It is a PHP file that contains the HTML and PHP codes for the elements and displays the retrieved data. This file is located in the resources/views directory of the project.

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.     <meta charset="UTF-8">
  4.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Sample Data Pagination with Live Search using Ajax</title>
  7.     <!-- Bootstrap CDN Link -->
  8.     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
  9.     <!-- Fontawesome CDN Link -->
  10.     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  11.     <!-- jQuery CDN JS -->
  12.     <script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>
  13.     <!-- Bootstrap CDN JS -->
  14.     <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
  15.     <!-- Fontawesome CDN JS -->
  16.     <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js" integrity="sha512-fD9DI5bZwQxOi7MhYWnnNPlvXdp/2Pj3XSTRrFs5FQa4mizyGLnJcN6tuvUS6LbmgN1ut+XGSABKvjN0H6Aoow==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  17. </head>
  18.     <div class="container-md py-5">
  19.         <div class="col-lg-5 col-md-6 col-sm-12 col-12 mx-auto my-2">
  20.             <!-- Search Box -->
  21.             <div class="input-group">
  22.                 <span class="input-group-text" id="basic-addon1">@</span>
  23.                 <input type="search" class="form-control rounded-0" id="search" placeholder="Search here..." value="{{$kw}}">
  24.             </div>
  25.             <!-- Search Box -->
  26.         </div>
  27.         <div class="table-responsive">
  28.             <!-- Data Table -->
  29.             <table id="membersTbl" class="table table-sm table-bordered table-striped">
  30.                 <thead>
  31.                     <tr>
  32.                         <th>ID</th>
  33.                         <th>Name</th>
  34.                         <th>Email</th>
  35.                         <th>Phone</th>
  36.                     </tr>
  37.                 </thead>
  38.                 <tbody>
  39.                     @foreach($members as $member)
  40.                         <tr>
  41.                             <td class="text-center">{{$member->id}}</td>
  42.                             <td>{{$member->name}}</td>
  43.                             <td>{{$member->email}}</td>
  44.                             <td>{{$member->phone}}</td>
  45.                         </tr>
  46.                     @endforeach
  47.                     @if(count($members) <= 0)
  48.                        <tr>
  49.                             @if(empty($kw))
  50.                             <!-- If No data to display -->
  51.                             <td class="text-center" colspan="4">No Data found</td>
  52.                             @else
  53.                             <!-- If No Data match the keyword -->
  54.                             <td class="text-center" colspan="4">No search keyword match found.</td>
  55.                             @endif
  56.                         </tr>
  57.                     @endif
  58.                 </tbody>
  59.             </table>
  60.             <!-- Data Table -->
  61.  
  62.             <!-- Pagination Link Wrapper -->
  63.             <div id="pagination-links">
  64.             {{$members->onEachSide(2)->links()}}
  65.             </div>
  66.             <!-- Pagination Link Wrapper -->
  67.         </div>
  68.     </div>    
  69. </body>
  70.     // Ajax Variable
  71.     var search_ajax;
  72.     $(document).ready(function(){
  73.         // Execute Live Searcing when search box input has character entered or change
  74.         $('#search').on('input change', function(e){
  75.             e.preventDefault()
  76.             // current keyword value
  77.             var searchTxt = $(this).val()
  78.             // Get Url Parameters
  79.             var urlParams = new URLSearchParams(location.search);
  80.             // New Parameters aray
  81.             var newParams = []
  82.             urlParams.forEach((v, k) => {
  83.                 if(k == 'q'){
  84.                     // update keyword value
  85.                     v = searchTxt
  86.                 }
  87.                 // Add parameter to the new parameter
  88.                 if(searchTxt != "" && k == 'q')
  89.                    newParams.push(`${k}=${encodeURIComponent(v)}`);
  90.             })
  91.             // Update Location URL without reloading the page
  92.             if(newParams.length > 0){
  93.                 // structuring the new URL
  94.                 var newLink = `{{URL::to('/')}}?`+(newParams.join('&'));
  95.                 // Update the location URL
  96.                 history.pushState({}, "", newLink)
  97.             }else{
  98.                 if(searchTxt != ""){
  99.                     // Update location URL
  100.                     history.pushState({}, "", `{{URL::to('/')}}?q=${encodeURIComponent(searchTxt)}`)
  101.                 }else{
  102.                     // Update location URL
  103.                     history.pushState({}, "", `{{URL::to('/')}}`)
  104.                 }
  105.  
  106.             }
  107.  
  108.             if(search_ajax != undefined && search_ajax != null){
  109.                // Abort Previous Search Ajax Process if exists
  110.                search_ajax.abort();
  111.             }
  112.             // Start Search Ajax Process
  113.             search_ajax = $.ajax({
  114.                 url:`{{URL::to('search')}}?q=${searchTxt}`,
  115.                 dataType:'json',
  116.                 error: err => {
  117.                     console.log(err)
  118.                     if(err.statusText != 'abort')
  119.                         alert('An error occurred');
  120.                 },
  121.                 success: function(resp){
  122.                     if(!!resp.members){
  123.                         // Data Table Body Element
  124.                         var tblBody = $('#membersTbl tbody')
  125.                         // Page Links Wrapper Element
  126.                         var paginationLink = $('#pagination-links')
  127.                         // remove current data on the table
  128.                         tblBody.html('')
  129.                         // remove current pagination links
  130.                         paginationLink.html('')
  131.                         if(!!resp.members.data){
  132.                             // Loop the searched data
  133.                             Object.values(resp.members.data).map(member => {
  134.                                 // creating new table row
  135.                                 var tr = $('<tr>')
  136.                                 // creting the new columns and data of the row
  137.                                 tr.append(`<td class="text-center">${member.id}</td>`)
  138.                                 tr.append(`<td>${member.name}</td>`)
  139.                                 tr.append(`<td>${member.email}</td>`)
  140.                                 tr.append(`<td>${member.phone}</td>`)
  141.                                 // inserting the created data row the table
  142.                                 tblBody.append(tr)
  143.                             })
  144.  
  145.                             if(Object.keys(resp.members.data).length <= 0){
  146.                                // Display Message if no data found that is match to the keyword
  147.                                var tr = $('<tr>')
  148.                                 tr.append(`<td class="text-center" colspan="4">No search keyword match found.</td>`)
  149.                                 tblBody.append(tr)
  150.                             }
  151.                         }
  152.                         // Update Pagination link
  153.                         if(!!resp.members.pagination_links)
  154.                             paginationLink.html(resp.members.pagination_links)
  155.                     }
  156.                 }
  157.             })
  158.         })
  159.     })
  160. </html>

I used CDNs link for the sources of the Bootstrap, jQuery, and Fontwesome libraries or packages which means that an internet connection is a must when browsing the web page.

Controller

The PHP file script below is the modified file content of the membersController.php. It contains the modified script of the index method of the class for rendering the web page and the new method called search. The search method of this controller class is used for retrieving the search data that is executed through Ajax Request. This file can be found in the apps/Http/Controllers directory.

  1. <?php
  2.  
  3. namespace App\Http\Controllers;
  4.  
  5. use App\Models\Members;
  6. use Illuminate\Http\Request;
  7.  
  8. class MembersController extends Controller
  9. {
  10.     /**
  11.         * Display a listing of the resource.
  12.         */
  13.     public function index(Request $request)
  14.     {
  15.         // search keyword
  16.         $kw = $request->q;
  17.  
  18.         if(empty($kw)){
  19.             // Display All data with pagination if no keyword to search
  20.             $members = Members::paginate(10);
  21.         }else{
  22.             // Display Filtered data with pagination if keyword exists
  23.             $members = Members::where('name', 'like' , "%{$kw}%")
  24.                                 ->orwhere('email', 'like' , "%{$kw}%")
  25.                                 ->orwhere('phone', 'like' , "%{$kw}%")
  26.                                 ->paginate(10)
  27.                                 ->appends(['q'=> "{$kw}"])
  28.                                 ->withPath('/')
  29.                                 ->withQueryString();
  30.         }
  31.         // render page view
  32.         return view('members', ['members'=>$members, 'kw' => $kw]);
  33.     }
  34.     /**
  35.         * Ajax Live Search Listing of the resource
  36.         */
  37.     public function search(Request $request){
  38.         // search keyword
  39.         $kw = $request->q;
  40.         if(empty($kw)){
  41.             // Display All data with pagination if no keyword to search
  42.             $members = Members::paginate(10);
  43.         }else{
  44.             // Display Filtered data with pagination if keyword exists
  45.             $members = Members::where('name', 'like' , "%{$kw}%")
  46.                                 ->orwhere('email', 'like' , "%{$kw}%")
  47.                                 ->orwhere('phone', 'like' , "%{$kw}%")
  48.                                 ->paginate(10)
  49.                                 ->appends(['q'=> "{$kw}"])
  50.                                 ->withPath('/')
  51.                                 ->withQueryString();
  52.         }
  53.        
  54.         // converting array to laravel collection
  55.         $membersCollection = collect($members);
  56.         // merging queried data with pagination links HTML
  57.         $membersCollection = $membersCollection->merge(['pagination_links' => (string) $members->onEachSide(2)->links()]);
  58.  
  59.         // returning the response data as JSON string
  60.         return collect(["members" => $membersCollection->all()])->toJson();
  61.     }
  62.     /**
  63.         * Show the form for creating a new resource.
  64.         */
  65.     public function create()
  66.     {
  67.         //
  68.     }
  69.  
  70.     /**
  71.         * Store a newly created resource in storage.
  72.         */
  73.     public function store(Request $request)
  74.     {
  75.         //
  76.     }
  77.  
  78.     /**
  79.         * Display the specified resource.
  80.         */
  81.     public function show(Members $members)
  82.     {
  83.         //
  84.     }
  85.  
  86.     /**
  87.         * Show the form for editing the specified resource.
  88.         */
  89.     public function edit(Members $members)
  90.     {
  91.         //
  92.     }
  93.  
  94.     /**
  95.         * Update the specified resource in storage.
  96.         */
  97.     public function update(Request $request, Members $members)
  98.     {
  99.         //
  100.     }
  101.  
  102.     /**
  103.         * Remove the specified resource from storage.
  104.         */
  105.     public function destroy(Members $members)
  106.     {
  107.         //
  108.     }
  109. }
  110.    

Routes

Finally, here's the last modified PHP file known as web.php. The file contains the routing script of the project for viewing the page content and retrieving data using Ajax Request. The file is located in the routes directory.

  1. <?php
  2.  
  3. use Illuminate\Support\Facades\Route;
  4. use App\Http\Controllers\MembersController;
  5.  
  6. /*
  7. |--------------------------------------------------------------------------
  8. | Web Routes
  9. |--------------------------------------------------------------------------
  10. |
  11. | Here is where you can register web routes for your application. These
  12. | routes are loaded by the RouteServiceProvider and all of them will
  13. | be assigned to the "web" middleware group. Make something great!
  14. |
  15. */
  16.  
  17. // Route::get('/', function () {
  18. //     return view('welcome');
  19. // });
  20. Route::controller(MembersController::class)->group(function(){
  21.     Route::get('/', 'index');
  22.     Route::get('/search', 'search');
  23. });

Snapshots

Here are some snapshots of the modified Laravel Project.

Page Interface

Data Table Pagination with Live Search using Laravel, jQuery, and Ajax Request

Sample Search Result #1

Data Table Pagination with Live Search using Laravel, jQuery, and Ajax Request

Sample Search Result #2

Data Table Pagination with Live Search using Laravel, jQuery, and Ajax Request

There you go! I also have provided the complete modified source code zip file of the sample Laravel Project on this website and it is free to download. The download button can be found below this tutorial's content. Feel free to download and modify the source code the way you wanted to enhance your programming capabilities using PHP and Laravel 10 Framework.

How to Run the source code?

  • Please start the Apache and MySQL servers of your XAMPP or equivalent software.
  • Extract the source code folder into the XAMPP's htdocs directory or equivalent directory.
  • Create a new database named dummy_db
  • Open the terminal or command prompt and redirect the directory to the source code folder
  • Run the php artisan migrate command
  • Run the php artisan make:seeder MembersSeeder command
  • Run the php artisan serve command
  • Browse the application. http://127.0.0.1:8000

That's it! I hope this Data Table Pagination with Live Search using Laravel, jQuery, and Ajax Request Tutorial will help you with what you are looking for and you'll find something useful for your current and future PHP or Laravel Projects.

Explore more on this website for more Tutorials and Free Source Codes.

Happy Coding =)

Add new comment