Ajax CRUD Application in Laravel 11 Tutorial

In this Laravel 11 Ajax CRUD tutorial, you will discover how to build a straightforward AJAX CRUD application in Laravel 11, step by step. The simple and easy way example to explain Ajax crud with Laravel 10 framework (create, read the update, delete) without page refresh or reload.

Using this Laravel 11 Ajax CRUD operations we will cover, to integrate bootstrap modal, datatables for enhanced data presentation, validation error handling, search, sorting, pagination, and seamless backend communication via Ajax requests—all while maintaining a smooth user experience without refreshing the page.

Laravel 11 Ajax CRUD Operation Tutorial Example

Follow the following step-by-step guide Ajax crud in Laravel 11 application using bootstrap modal and datatables without page refresh and search sort functionality.

  • Install Laravel 11 App
  • Configure Database Credentials
  • Generate Model and Migration
  • Make Routes
  • Create Controller for Laravel Ajax CRUD
  • Create Blade View Files
  • Add jQuery Code for Ajax CRUD Laravel
  • Run your Application

#1 Install Laravel 11 App

Before proceeding with the installation of Laravel 11, ensure that your system meets the following prerequisites:

  • Laravel 11 requires PHP version 8.2 or higher. You can verify your PHP version by running php -v in your terminal or command prompt. If you don’t have PHP 8.2 installed, you’ll need to upgrade your PHP version.
  • Laravel supports multiple database systems such as MySQL, PostgreSQL, SQLite, and SQL Server. In Laravel 11, they have predefined DB_CONNECTION=sqlite in the .env file, but if you are using MySQL, you will need to update it.

To install Laravel 11, run the following command in your terminal:

composer create-project laravel/laravel:^11.0 laravel-ajax-crud

If you prefer to install Laravel based on your PHP version, use the following command:

composer create-project laravel/laravel laravel-ajax-crud

Next, navigate to the project directory:

cd laravel-ajax-crud

#2 Connect App to Database

Open the .env file located at root directory and add the DB_CONNECTION, database name, username, and password.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=#db_name
DB_USERNAME=#db_username
DB_PASSWORD=#db_password

#3 Create Model and Migration

Next, you need to create a model and migration file in Laravel app. For generating the Model and Migration file your just need to run the following command.

php artisan make:model Post -m

After that navigate database\migrations and open the 2024_03_18_074219_create_posts_table.php file and update the below code on it.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id('uuid');
            $table->string('title');
            $table->text('description')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};

Now, run the migrate command to generate the table in the database.

php artisan migrate

Now open your model app\Models\Post.php and add the fallible properties same as below.

<?php

namespace App\Models;

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

class Post extends Model
{
    use HasFactory;

    public $fillable = ['title', 'description'];
}

#4 Create Routes in Laravel

Now open your routes/web.php file and put the resource routes on it. This resource route handles your all Laravel ajax crud operation.

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ContactController;
use App\Http\Controllers\PostController;

Route::resource('posts', PostController::class)->names('posts');

#5 How to Create Controller

Now create a new controller using running the below command.

php artisan make:controller PostController --resource

After successfully creating the controller, now open the app/Http/Controllers/PostController.php file and put the methods on it.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;
use App\Models\Category;
use App\Models\PostCategory;
use Illuminate\Support\Str;

class PostController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        $posts = Post::orderBy('id','desc')->paginate(10);

        if ($request->ajax()) {
            return response()->json([
                'html' => view('posts-list', compact('posts'))->render()
            ]);
        }
    
        return view('posts', compact('posts'));
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required|max:255',
            'description' => 'nullable|string',
        ]);

        $post = Post::updateOrCreate(['id' => $request->id], $request->only('title', 'description'));

        return response()->json(['code' => 200, 'message' => 'Post created successfully', 'data' => $post], 200);
    }

    /**
     * Display the specified resource.
     */
    public function show($id)
    {
        $post = Post::findOrFail($id);

        return response()->json($post);
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy($id)
    {
        $post = Post::findOrFail($id);
        $post->delete();

        return response()->json(['message' => 'Post deleted successfully'], 200);
    }

    function getUuid() {
        return Str::uuid();
    }
}

#6 Create Blade Files

In this step create a posts.blade.php blade file in your resources/views directory and then open the resources\views\posts.blade.php file and update the below code on it.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="csrf-token" content="{{ csrf_token() }}">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
  <link rel="stylesheet" href="https://cdn.datatables.net/r/bs-3.3.5/jq-2.1.4,dt-1.10.8/datatables.min.css"/>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
  <script src="https://cdn.datatables.net/r/bs-3.3.5/jqc-1.11.3,dt-1.10.8/datatables.min.js"></script>
</head>
  <style>
  .alert-message {
    color: red;
  }
</style>
<body>
    <div class="container">
        <!-- <h2 style="margin-top: 12px;" class="alert alert-success">Ajax CRUD with Laravel App</h2><br> -->

        <div class="row">
            <div class="col-12 text-right">
                <a href="javascript:void(0)" class="btn btn-success mb-3" id="create-new-post" onclick="addPost()">Add Post</a>
            </div>
        </div>
        
        <div id="posts-list" class="row" style="clear: both; margin-top: 18px;">
            @include('posts-list', $posts)
        </div>
        
        <div class="modal fade" id="post-modal" aria-hidden="true">
          <div class="modal-dialog">
              <div class="modal-content">
                  <div class="modal-header">
                    <h5 class="modal-title">Add/Edit Post</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"  onclick="closeModal()">
                      <span aria-hidden="true">&times;</span>
                    </button>
                  </div>
                  <div class="modal-body">
                      <form name="userForm" class="form-horizontal">
                      <input type="hidden" name="post_id" id="post_id">
                          <div class="form-group">
                              <label for="name" class="col-sm-2">title</label>
                              <div class="col-sm-12">
                                  <input type="text" class="form-control" id="title" name="title" placeholder="Add title">
                                  <span id="titleError" class="alert-message"></span>
                              </div>
                          </div>
                          <div class="form-group">
                              <label class="col-sm-2">Description</label>
                              <div class="col-sm-12">
                                  <textarea class="form-control" id="description" name="description" placeholder="Add description" rows="4" cols="50"></textarea>
                                  <span id="descriptionError" class="alert-message"></span>
                              </div>
                          </div>
                      </form>
                  </div>
                  <div class="modal-footer">
                      <button type="button" class="btn btn-default" onclick="closeModal()">Close</button>
                      <button type="button" class="btn btn-primary" onclick="createPost()">Save</button>
                  </div>
              </div>
          </div>
      </div>

    </div>

    <script>
      $('#laravel-ajax-crud').DataTable();

      function addPost() {
        $("#post_id").val('');
        $('#post-modal').modal('show');
      }

      function editPost(event) {
        const postId  = $(event).data("id");

        $('#titleError').text('');
        $('#descriptionError').text('');

        $.ajax({
          url: `/posts/${postId}`,
          type: "GET",
          success: function(response) {
            if (response) {
                $("#post_id").val(response.id);
                $("#title").val(response.title);
                $("#description").val(response.description);
                $('#post-modal').modal('show');
            }
          }
        });
      }

      function createPost() {
        const title = $('#title').val();
        const description = $('#description').val();
        const postId = $('#post_id').val();

        $.ajax({
            url: `/posts`,
            type: "POST",
            data: {
              id: postId,
              title: title,
              description: description,
              _token: $('meta[name="csrf-token"]').attr('content')
            },
            success: function(response) {
                if (response.code == 200) {
                  getPosts();
                  closeModal();
              }
            },
            error: function(response) {
              $('#titleError').text(response.responseJSON.errors.title);
              $('#descriptionError').text(response.responseJSON.errors.description);
            }
          });
      }

      function getPosts() {
        $.ajax({
          url: `/posts`,
          type: "GET",
          success: function(response) {
            console.log(response);
            $("#posts-list").html(response.html);
          }
        });
      }

      function deletePost(event) {
        const postId = $(event).data("id");

        $.ajax({
            url: `/posts/${postId}`,
            type: 'DELETE',
            data: {
              _token: $('meta[name="csrf-token"]').attr('content')
            },
            success: function(response) {
              $("#row_"+postId).remove();
            }
          });
      }

      function closeModal() {
        $('#title').val('');
        $('#titleError').text('');
        $('#description').val('');
        $('#post-modal').modal('hide');
      }

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

Next, create another file named as posts-list.blade.php in your routes/views directory. This will be shown in the ajax render case when you create or update data this page will show the list of pots.

So, open the resources\views\posts-list.blade.php file and update the below code on it.

<div class="col-12">
    <table id="laravel-ajax-crud" class="table table-striped table-bordered">
        <thead>
            <tr>
                <th>Title</th>
                <th>Description</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            @foreach($posts as $post)
                <tr id="row_{{$post->id}}">
                    <td>{{ $post->title }}</td>
                    <td>{{ $post->description }}</td>
                    <td>
                        <a href="javascript:void(0)"data-id="{{ $post->id }}" onclick="editPost(event.target)" class="btn btn-info">Edit</a>
                        <a href="javascript:void(0)"data-id="{{ $post->id }}" onclick="deletePost(event.target)" class="btn btn-danger">Delete</a>
                    </td>
                </tr>
            @endforeach
        </tbody>
    </table>
</div>

#7 Add Bootstrap Modal

After adding the posts blade file, now add the bootstrap model code in your “posts.blade.php” after the last closing div.

<div class="modal fade" id="post-modal" aria-hidden="true">
  <div class="modal-dialog">
      <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">Add/Edit Post</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"  onclick="closeModal()">
              <span aria-hidden="true">&times;</span>
            </button>
          </div>
          <div class="modal-body">
              <form name="userForm" class="form-horizontal">
              <input type="hidden" name="post_id" id="post_id">
                  <div class="form-group">
                      <label for="name" class="col-sm-2">title</label>
                      <div class="col-sm-12">
                          <input type="text" class="form-control" id="title" name="title" placeholder="Add title">
                          <span id="titleError" class="alert-message"></span>
                      </div>
                  </div>
                  <div class="form-group">
                      <label class="col-sm-2">Description</label>
                      <div class="col-sm-12">
                          <textarea class="form-control" id="description" name="description" placeholder="Add description" rows="4" cols="50"></textarea>
                          <span id="descriptionError" class="alert-message"></span>
                      </div>
                  </div>
              </form>
          </div>
          <div class="modal-footer">
              <button type="button" class="btn btn-default" onclick="closeModal()">Close</button>
              <button type="button" class="btn btn-primary" onclick="createPost()">Save</button>
          </div>
      </div>
  </div>
</div>

#8 Send Ajax request for CRUD operation

Now add jquery and Ajax code in your “posts.blade.php” file after closing in the body tag for Laravel Ajax crud operation.

<script>
  $('#laravel-ajax-crud').DataTable();

  function addPost() {
    $("#post_id").val('');
    $('#post-modal').modal('show');
  }

  function editPost(event) {
    const postId  = $(event).data("id");

    $('#titleError').text('');
    $('#descriptionError').text('');

    $.ajax({
      url: `/posts/${postId}`,
      type: "GET",
      success: function(response) {
        if (response) {
            $("#post_id").val(response.id);
            $("#title").val(response.title);
            $("#description").val(response.description);
            $('#post-modal').modal('show');
        }
      }
    });
  }

  function createPost() {
    const title = $('#title').val();
    const description = $('#description').val();
    const postId = $('#post_id').val();

    $.ajax({
        url: `/posts`,
        type: "POST",
        data: {
          id: postId,
          title: title,
          description: description,
          _token: $('meta[name="csrf-token"]').attr('content')
        },
        success: function(response) {
            if (response.code == 200) {
              getPosts();
              closeModal();
          }
        },
        error: function(response) {
          $('#titleError').text(response.responseJSON.errors.title);
          $('#descriptionError').text(response.responseJSON.errors.description);
        }
      });
  }

  function getPosts() {
    $.ajax({
      url: `/posts`,
      type: "GET",
      success: function(response) {
        console.log(response);
        $("#posts-list").html(response.html);
      }
    });
  }

  function deletePost(event) {
    const postId = $(event).data("id");

    $.ajax({
        url: `/posts/${postId}`,
        type: 'DELETE',
        data: {
          _token: $('meta[name="csrf-token"]').attr('content')
        },
        success: function(response) {
          $("#row_"+postId).remove();
        }
      });
  }

  function closeModal() {
    $('#title').val('');
    $('#titleError').text('');
    $('#description').val('');
    $('#post-modal').modal('hide');
  }

</script>

So your posts.blade.php file full code looks like this:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="csrf-token" content="{{ csrf_token() }}">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
  <link rel="stylesheet" href="https://cdn.datatables.net/r/bs-3.3.5/jq-2.1.4,dt-1.10.8/datatables.min.css"/>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
  <script src="https://cdn.datatables.net/r/bs-3.3.5/jqc-1.11.3,dt-1.10.8/datatables.min.js"></script>
</head>
  <style>
  .alert-message {
    color: red;
  }
</style>
<body>
    <div class="container">
        <!-- <h2 style="margin-top: 12px;" class="alert alert-success">Ajax CRUD with Laravel App</h2><br> -->

        <div class="row">
            <div class="col-12 text-right">
                <a href="javascript:void(0)" class="btn btn-success mb-3" id="create-new-post" onclick="addPost()">Add Post</a>
            </div>
        </div>
        
        <div id="posts-list" class="row" style="clear: both; margin-top: 18px;">
            @include('posts-list', $posts)
        </div>
        
        <div class="modal fade" id="post-modal" aria-hidden="true">
          <div class="modal-dialog">
              <div class="modal-content">
                  <div class="modal-header">
                    <h5 class="modal-title">Add/Edit Post</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"  onclick="closeModal()">
                      <span aria-hidden="true">&times;</span>
                    </button>
                  </div>
                  <div class="modal-body">
                      <form name="userForm" class="form-horizontal">
                      <input type="hidden" name="post_id" id="post_id">
                          <div class="form-group">
                              <label for="name" class="col-sm-2">title</label>
                              <div class="col-sm-12">
                                  <input type="text" class="form-control" id="title" name="title" placeholder="Add title">
                                  <span id="titleError" class="alert-message"></span>
                              </div>
                          </div>
                          <div class="form-group">
                              <label class="col-sm-2">Description</label>
                              <div class="col-sm-12">
                                  <textarea class="form-control" id="description" name="description" placeholder="Add description" rows="4" cols="50"></textarea>
                                  <span id="descriptionError" class="alert-message"></span>
                              </div>
                          </div>
                      </form>
                  </div>
                  <div class="modal-footer">
                      <button type="button" class="btn btn-default" onclick="closeModal()">Close</button>
                      <button type="button" class="btn btn-primary" onclick="createPost()">Save</button>
                  </div>
              </div>
          </div>
        </div>

    </div>

    <script>
      $('#laravel-ajax-crud').DataTable();

      function addPost() {
        $("#post_id").val('');
        $('#post-modal').modal('show');
      }

      function editPost(event) {
        const postId  = $(event).data("id");

        $('#titleError').text('');
        $('#descriptionError').text('');

        $.ajax({
          url: `/posts/${postId}`,
          type: "GET",
          success: function(response) {
            if (response) {
                $("#post_id").val(response.id);
                $("#title").val(response.title);
                $("#description").val(response.description);
                $('#post-modal').modal('show');
            }
          }
        });
      }

      function createPost() {
        const title = $('#title').val();
        const description = $('#description').val();
        const postId = $('#post_id').val();

        $.ajax({
            url: `/posts`,
            type: "POST",
            data: {
              id: postId,
              title: title,
              description: description,
              _token: $('meta[name="csrf-token"]').attr('content')
            },
            success: function(response) {
                if (response.code == 200) {
                  getPosts();
                  closeModal();
              }
            },
            error: function(response) {
              $('#titleError').text(response.responseJSON.errors.title);
              $('#descriptionError').text(response.responseJSON.errors.description);
            }
          });
      }

      function getPosts() {
        $.ajax({
          url: `/posts`,
          type: "GET",
          success: function(response) {
            console.log(response);
            $("#posts-list").html(response.html);
          }
        });
      }

      function deletePost(event) {
        const postId = $(event).data("id");

        $.ajax({
            url: `/posts/${postId}`,
            type: 'DELETE',
            data: {
              _token: $('meta[name="csrf-token"]').attr('content')
            },
            success: function(response) {
              $("#row_"+postId).remove();
            }
          });
      }

      function closeModal() {
        $('#title').val('');
        $('#titleError').text('');
        $('#description').val('');
        $('#post-modal').modal('hide');
      }

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

#9 Start your App and test

In the last step, open the command prompt and run the following command to start the development server:

php artisan serve

Then open your browser and hit the following URL on it:

https://localhost:8000/posts