Skip to content
Readerstacks logo Readerstacks
  • Home
  • Softwares
  • Angular
  • Php
  • Laravel
  • Flutter
Readerstacks logo
Readerstacks
Laravel 9 Ajax CRUD with Search, Image and Pagination

Laravel 9 Ajax CRUD with Search, Image and Pagination

Aman Jain, June 26, 2022March 28, 2023

In this article i will learn Ajax CRUD with Search, Image and Pagination in laravel 9. When we want to perform the CRUD operations without reloading the page then we use javascript and Ajax to refresh the page content without reloading.In this post we will not only cover the Ajax CRUD operation but also the validation on form, unique validation, image uploading and view the uploaded image, Flash messages, Search the uploaded data and many more.

This is important we learn each and every aspect of crud and the above the crud like uploading , searching and all. As we know CRUD is full form is Create, Read, Update and Delete. Crud is the basic operation is in all programming languages and we will cover all the aspects in this tutorial.

We will use bootstrap and jQuery to perform javascript based operation. We will use $.ajax to communicate with server.

In the example first we will create a project then make the appropriate database connections to connect our application with mysql. After that we will create a resource controller which gives us default routes for add edit and delete functionalities.

In our list page we will include the pagination and searching as well so user can search by email and title easily. Pagination to show data in chunk that will optimize our page to load data on request. In our form page we will take 4 fields title, email , body and Image. I figured it out that most of the laravel crud examples do not cover the unique and image uploading but here we will cover that too.

So let’s learn Laravel 9 Ajax CRUD with Search, Image and Pagination step by step

Step 1: Create a laravel project

First step is to create the Laravel 9 project using composer command or you can also read the How to install laravel 8 ? and Laravel artisan command to generate controllers, Model, Components and Migrations

composer create-project laravel/laravel crud

Step 2: Configure database

Next step is to configure the database for our project, table and data. So open .env or if file not exist then rename .env.example file to .env file in root folder and change below details

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

Step 3: Create Model and Migration

If you have table and large data already then you can skip this step but if you are beginner and trying to implement Crud then in this step we are creating a model and migration using artisan command

php artisan make:model Article -m

Above command will create two files one is migration and other one is model. open migration file which is located at database/migrations/timestamp_create_articles_table.php and edit the schema as below

  public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->id();
            $table->string('email')->unique();;
            $table->string('title');
            $table->string('body')->nullable();;
            $table->string('image');
            $table->timestamps();
        });
    }

Run migration using artisan command in command line

php artisan migrate

Output of above command

Migrating: 2022_06_25_112800_create_articles_table
Migrated:  2022_06_25_112800_create_articles_table (45.63ms)

Step 4 : Create a controller

Next, Create the resource controller and add the necessary imports and class. You can create by Laravel artisan or manually.

php artisan make:controller ArticleController --resource

Now, add the controller logic for pagination

<?php

namespace App\Http\Controllers;

use App\Models\Article;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class ArticleController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $articles = Article::when($request->has("title"), function ($q) use ($request) {
            return $q->where("title", "like", "%" . $request->get("title") . "%");
            })
            ->when($request->has("email"), function ($q) use ($request) {
                return $q->where("email", "like", "%" . $request->get("email") . "%");
            })
            ->orderBy("id","DESC")->paginate(2);
            
            if($request->ajax()){
                return view('articles.article-pagination ',['articles'=>$articles]); 
            } 

            return view('articles.list ',['articles'=>$articles]);
    }
 
    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $validations=[
            'title' => "required",
            'email' => "required|email|unique:articles,email,".$request->id,
            'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:4096',
        ];

        if($request->id!="" && !$request->hasFile("image")){
                $validations['image']=""; 
        }

        $validator = Validator::make($request->all(), $validations);


        if ($validator->fails()) {
            return response()->json($validator->errors(),422);
            
        }
       

        //  save image and name in database
        if($request->id==''){
            $Article = new Article();
        }
        else{
            $Article =   Article::find($request->id);
        }
       
        $Article->title = $request->title;
        $Article->email = $request->email;
        if($request->hasFile("image")){
            $file = $request->file("image")->store("uploads/images");
            $Article->image = $file;
        }
       
        $Article->body  = $request->body;
        $Article->save();
        return response()->json(["status" => true, "message" => "You have successfully created the article."]);
        
    }
 
    public function destroy($id)
    {
        Article::find($id)->delete();
        return response()->json(["status" => true, "message" => "Record deleted successfully"]);
        
    }
}

So as you can see we have created multiple methods and created their definitions in the method. So in index method we have simply fetched the all records from atricles table using model Article along with searching.

Then, we have store method where we have defined the validation rules and the definition logic for add and update the data in article table along with image uploading.

So to configure the images we need tp create Symblink as follow

This is an important step and i suggest you to not skip this step, if you are going to show images in your website because you must need to access the image to show it on website so open config\filesystems.php and add public_path('uploads') => storage_path('app/uploads') to links block

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Default Filesystem Disk
    |--------------------------------------------------------------------------
    |
    | Here you may specify the default filesystem disk that should be used
    | by the framework. The "local" disk, as well as a variety of cloud
    | based disks are available to your application. Just store away!
    |
    */

    'default' => env('FILESYSTEM_DRIVER', 'public'),
    'disks' => [

        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],

        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
        ],

        's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
            'endpoint' => env('AWS_ENDPOINT'),
            'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
        ],

    ],
    'links' => [
        public_path('storage') => storage_path('app/public'),
        public_path('uploads') => storage_path('app/uploads'),
    ],

];

Since we are using in our controller this code

$destinationPath= '/uploads/images';
         
$storageDestinationPath=storage_path('app'.$destinationPath);

so we created a Symblink as

 public_path('uploads') => storage_path('app/uploads'),

Now run artisan command to run Symblink

php artisan storage:link

You can read Full article here How to access and setup storage files after upload in laravel ?

Step 5 : Create the views

Create two views one for full page and other for list with pagination therefore creating views in resource/articles/article.blade.php and resource/articles/article-pagination.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Laravel 9 AJAX CRUD with Search, Image and Pagination -Readerstacks</title>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>
</head>

<body class="antialiased">
    <div class="container">
        <!-- main app container -->
        <div class="readersack">
            <div class="container">
                <div class="row">
                    <div class="col-md-12 ">
                        <h3>Laravel 9 AJAX CRUD with Search, Image and Pagination -Readerstacks</h3>

                        <button type="button" class="btn btn-info" data-toggle="modal" data-target="#addupdatepopup">
                            Add New Article
                        </button>
                        <div id="search">
                            <form id="searchform" name="searchform">
                                <div class="form-group">
                                    <label>Search by Title</label>
                                    <input type="text" name="title" value="{{request()->get('title','')}}" class="form-control" />
                                    @csrf

                                </div>
                                <div class="form-group">
                                    <label>Search by body</label>
                                    <input type="text" name="body" value="{{request()->get('body','')}}" class="form-control" />


                                </div>
                                <a class='btn btn-success' href='{{url("articles")}}' id='search_btn'>Search</a>
                            </form>


                        </div>
                        <div id="pagination_data">
                            @include("articles.article-pagination",["articles"=>$articles])
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- credits -->
        <div class="text-center">
            <p>
                <a href="#" target="_top">Laravel 9 AJAX CRUD with Search, Image and Pagination -Readerstacks
                </a>
            </p>
            <p>
                <a href="https://readerstacks.com" target="_top">readerstacks.com</a>
            </p>
        </div>
    </div>
    <div class="modal" id="addupdatepopup" tabindex="-1" role="dialog">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <form action="{{ url('articles') }}" class="formsubmit" method="POST" enctype="multipart/form-data">
                    <div class="modal-header">
                        <h5 class="modal-title">Article</h5>
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true">×</span>
                        </button>
                    </div>
                    <div class="modal-body">

                        @csrf
                        <div class="row">
                            <input type="hidden" placeholder="id" value="" name="id">


                            <div class="col-12">
                                <label>Title</label>
                                <input type="text" placeholder="Title" value="{{ old('title') }}" name="title" class="form-control">
                            </div>
                            <div class="col-12">
                                <label>Email</label>
                                <input type="email" placeholder="Email" value="{{ old('email') }}" name="email" class="form-control">
                            </div>
                            <div class="col-12">
                                <label>Body</label>
                                <input type="text" placeholder="Body" value="{{ old('body') }}" name="body" class="form-control">
                            </div>
                            <div class="col-12">
                                <label>Image</label>
                                <div>
                                    <input type="file" placeholder="Image" name="image" id="imgInp">
                                    <img style="visibility:hidden" id="prview" src="" width=100 height=100 />
                                </div>


                            </div>
                        </div>


                    </div>
                    <div class="modal-footer">
                        <button type="submit" class="btn btn-primary">Save</button>
                        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
    <script>
        $(function() {
            $('#addupdatepopup').on('show.bs.modal', function(e) {  // reste the form on open of modal
                $("#addupdatepopup").find("[name='title']").val('');
                $("#addupdatepopup").find("[name='email']").val('');
                $("#addupdatepopup").find("[name='body']").val('');
                $("#addupdatepopup").find("[name='id']").val('');
                $("#addupdatepopup").find("[name='image']").val(null);
                $("#addupdatepopup").find("#prview").css("visibility", "hidden");
                $("#addupdatepopup").find("#prview").attr("src", '');
            });
            $(document).on("click", ".edit-article", function(e) {  // on click of edit button prefilled the form
                e.preventDefault();
                var article = $(this).data("json");
                $("#addupdatepopup").modal("show")
                $("#addupdatepopup").find("[name='title']").val(article.title);
                $("#addupdatepopup").find("[name='email']").val(article.email);
                $("#addupdatepopup").find("[name='body']").val(article.body);
                $("#addupdatepopup").find("[name='id']").val(article.id);

                $("#addupdatepopup").find("#prview").css("visibility", "visible");
                $("#addupdatepopup").find("#prview").attr("src", article.image);
                return false;
            });

            $(document).on("submit", ".formsubmit", function(e) { // handle form submit and run the ajax
                e.preventDefault();
                var action = $(this).attr("action");
                var method = $(this).attr("method");
                var formData = new FormData(this);
                callAjax(action, method, formData)
            });


            $(document).on("click", "#pagination a,#search_btn", function() {

                //get url and make final url for ajax 
                var url = $(this).attr("href");
                var append = url.indexOf("?") == -1 ? "?" : "&";
                var finalURL = url + append + $("#searchform").serialize();

                //set to current url
                window.history.pushState({}, null, finalURL);

                getData(finalURL);

                return false;
            })

            function callAjax(action, method, formData) {
                $.ajax({
                    url: action,
                    type: method,
                    data: formData,
                    success: function(data) {
                        $(".alert").remove();
                        $("#addupdatepopup").modal("hide")
                        getData($("#search_btn").attr("href"));
                        alert(data.message);


                    },
                    error: function(response) {

                        //set the error messages
                        $(".alert").remove();
                        var erroJson = JSON.parse(response.responseText);
                        for (var err in erroJson) {
                            for (var errstr of erroJson[err])
                            $("#addupdatepopup").find("[name='" + err + "']").after("<div class='alert alert-danger'>" + errstr + "</div>");
                        }
                    },
                    cache: false,
                    contentType: false,
                    processData: false
                });
            }

            function getData(url) {
                $.get(url, function(data) {
                    $("#pagination_data").html(data);
                });
            }

        });
    </script>
</body>

</html>

As we can see i added bootstrap and jQuery as well. We also include @include("articles.article-pagination",["article"=>$article]) so we can show article on first render.

And resources/views/articles/article-pagination.blade.php

<table class="table table-striped table-dark table-bordered">
  <tr>
    <th>Sr No.</th>
    <th>Title</th>
    <th>Email</th>
    <th>Body</th>
    <th>Image</th>
    <th>Date</th>
    <th>Action</th>
  </tr>
  @foreach($articles as $article)
  <tr>
    <td>{{$article->id}}</td>
    <td>{{$article->title}}</td>
    <td>{{$article->email}}</td>
    <td>{{$article->body}}</td>
    <td><img src='{{$article->image}}' width=100 /></td>
    <td>{{$article->created_at}}</td>
    <td>
    <a href="{{route('articles.update',$article->id) }}" data-json="{{json_encode($article)}}" class="edit-article btn btn-success">Edit</a>
    <form action="{{ route('articles.destroy',$article->id) }}" class="formsubmit" method="Post">
        @csrf
        @method('DELETE')
        <button type="submit" class="btn btn-danger">Delete</button>
    </form>

    </td>
  </tr>
  @endforeach
</table>
<div id="pagination">
  {{ $articles->links() }}
</div>

Then we have jQuery to handle the pagination, edit, add, delete and search

  $(function() {
                $('#addupdatepopup').on('show.bs.modal', function(e) {  // reste the form on open of modal
                      $(".alert").remove();
                    $("#addupdatepopup").find("[name='title']").val('');
                    $("#addupdatepopup").find("[name='email']").val('');
                    $("#addupdatepopup").find("[name='body']").val('');
                    $("#addupdatepopup").find("[name='id']").val('');
                    $("#addupdatepopup").find("[name='image']").val(null);
                    $("#addupdatepopup").find("#prview").css("visibility", "hidden");
                    $("#addupdatepopup").find("#prview").attr("src", '');
                });
                $(document).on("click", ".edit-article", function(e) {  // on click of edit button prefilled the form
                    e.preventDefault();
                    var article = $(this).data("json");
                    $("#addupdatepopup").modal("show")
                    $("#addupdatepopup").find("[name='title']").val(article.title);
                    $("#addupdatepopup").find("[name='email']").val(article.email);
                    $("#addupdatepopup").find("[name='body']").val(article.body);
                    $("#addupdatepopup").find("[name='id']").val(article.id);

                    $("#addupdatepopup").find("#prview").css("visibility", "visible");
                    $("#addupdatepopup").find("#prview").attr("src", article.image);
                    return false;
                });

                $(document).on("submit", ".formsubmit", function(e) { // handle form submit and run the ajax
                    e.preventDefault();
                    var action = $(this).attr("action");
                    var method = $(this).attr("method");
                    var formData = new FormData(this);
                    callAjax(action, method, formData)
                });


                $(document).on("click", "#pagination a,#search_btn", function() {

                    //get url and make final url for ajax 
                    var url = $(this).attr("href");
                    var append = url.indexOf("?") == -1 ? "?" : "&";
                    var finalURL = url + append + $("#searchform").serialize();

                    //set to current url
                    window.history.pushState({}, null, finalURL);

                    getData(finalURL);

                    return false;
                })

                function callAjax(action, method, formData) {
                    $.ajax({
                        url: action,
                        type: method,
                        data: formData,
                        success: function(data) {
                            $(".alert").remove();
                            $("#addupdatepopup").modal("hide")
                            getData($("#search_btn").attr("href"));
                            alert(data.message);


                        },
                        error: function(response) {

                            //set the error messages
                            $(".alert").remove();
                            var erroJson = JSON.parse(response.responseText);
                            for (var err in erroJson) {
                                for (var errstr of erroJson[err])
                                $("#addupdatepopup").find("[name='" + err + "']").after("<div class='alert alert-danger'>" + errstr + "</div>");
                            }
                        },
                        cache: false,
                        contentType: false,
                        processData: false
                    });
                }

                function getData(url) {
                    $.get(url, function(data) {
                        $("#pagination_data").html(data);
                    });
                }



            });

This is the main part for Ajax pagination here we used jQuery to handle the click on li and search button. then on click we pushed the url and execute the ajax.

Step 6 : Create Route

Last and final step is to create the route for our resource controller to serve the CRUD

<?php

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


Route::resource('articles', ArticleController::class);

You can read more about resource controller How to create resource controller in Laravel 8 ?

Now run the the application using php artisan serve and check our implementation

Laravel Ajax CRUD with search pagination validation and image
Laravel Ajax CRUD with search pagination validation and image
Laravel Ajax CRUD with search pagination validation and image
Laravel Ajax CRUD with search pagination validation and image
Laravel Ajax CRUD with search pagination validation and image
Validation
Screenshot 2022 06 25 at 5.18.21 PM 1
List
Laravel Ajax CRUD with search pagination validation and image
Edit Form
Laravel Ajax CRUD with search pagination validation and image
Deleted Successfully

Related

Php Laravel 9 ajaxCRUDimagelaravelpaginationSearchvalidation

Post navigation

Previous post
Next post

Related Posts

How to find php.ini file location ?

August 24, 2021February 22, 2024

Sometime we installed multiple version of php on our system so it will get difficult to find php.ini file location . Let’s start with easiest way. Steps to find the php ini file on dedicated, localhost and ssh based enabled server. Then run this file in browser. As we can…

Read More
Javascript Laravel Customized Autocomplete JQuery UI

Laravel Customized Autocomplete JQuery UI

July 12, 2022July 12, 2022

Laravel Customized Autocomplete JQuery UI is useful when we want live search of bulk data. Autocomplete search is mostly work of javascript and when we want to fetch live data from database then we require the intervention of laravel to provide the data in json response. In this tutorial we…

Read More
Php How to use conditional orderby in Laravel 8

How to use conditional orderBy clause in Laravel 8 eloquent ?

February 12, 2022October 4, 2022

In Laravel sometimes while creating a eloquent or db builder query you wanted to apply the orderBy clause on basis of some conditions and to achieve it you may use if else condition but laravel 8 itself provides solution to handle such type of situations using when method. Laravel eloquent…

Read More

Aman Jain
Aman Jain

With years of hands-on experience in the realm of web and mobile development, they have honed their skills in various technologies, including Laravel, PHP CodeIgniter, mobile app development, web app development, Flutter, React, JavaScript, Angular, Devops and so much more. Their proficiency extends to building robust REST APIs, AWS Code scaling, and optimization, ensuring that your applications run seamlessly on the cloud.

Categories

  • Angular
  • CSS
  • Dart
  • Devops
  • Flutter
  • HTML
  • Javascript
  • jQuery
  • Laravel
  • Laravel 10
  • Laravel 11
  • Laravel 9
  • Mysql
  • Php
  • Softwares
  • Ubuntu
  • Uncategorized

Archives

  • May 2025
  • April 2025
  • October 2024
  • July 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • July 2023
  • March 2023
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • July 2022
  • June 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • June 2021

Recent Posts

  • Understanding High Vulnerabilities: A Deep Dive into Recent Security Concerns
  • Understanding High Vulnerabilities in Software: A Week of Insights
  • Blocking Spam Requests with LaraGuard IP: A Comprehensive Guide
  • Enhancing API Development with Laravel API Kit
  • Exploring the Future of Web Development: Insights from Milana Cap
©2023 Readerstacks | Design and Developed by Readerstacks
Go to mobile version