Simple Ajax CRUD Application in Laravel 11 Step-by-Step

Using this Laravel Ajax CRUD tutorial you will learn how to create a simple 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.

In this Laravel Ajax CRUD operation with validation example, we will use bootstrap modal, datatables, validation errors, search sort, and pagination functionality and send requests to the backend without refreshing the page.

We will create a posts crud operation in Laravel using Ajax requests to save, edit, update and delete data using resource controllers and routes.

How to Create Ajax CRUD in Laravel 11 with validation

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

  • Download 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 Download 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

Once the installation is complete, navigate to the project directory:

cd laravel-ajax-crud

#2 Configure Database Credentials

After that, add your database credentials to the .env file, such as the DB_CONNECTION, database name, username, and password. The .env file is located in your project’s root directory.

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 Generate Model and Migration

In the next step, 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. Here the -m generates posts migration automatically.

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

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 Create Controller for Laravel Ajax CRUD

Now create a new controller as PostController just 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 Add JS code and send Ajax request

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>

See Also: Laravel Datatables Example with AJAX Search and Sort

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

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

#10 Conclusion

This jQuery Laravel CRUD Ajax will be tested with the below Laravel version.

  • Laravel 8
  • Laravel 9
  • Laravel 10
  • Laravel 11

So, guys the Laravel 11 AJAX CRUD Example Tutorial From Scratch is over now. If you have any issues or query about Ajax crud with Laravel please comment to us