Laravel 12 provides powerful features for building web applications efficiently. When combined with AJAX, jQuery, and Bootstrap, it enables dynamic, interactive, and user-friendly CRUD operations without reloading the page.
In this tutorial, we will implement an AJAX-based CRUD (Create, Read, Update, Delete) system using Laravel 12 as the backend, jQuery for handling AJAX requests, and Bootstrap for styling the interface. This will allow seamless data interaction without full-page reloads.
Start by installing a fresh Laravel project:
composer create-project --prefer-dist laravel/laravel laravel12-ajax-crud
cd laravel12-ajax-crud
Set up the .env
file with database credentials:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_ajax_crud
DB_USERNAME=root
DB_PASSWORD=
Run database migrations:
php artisan migrate
We will create a model named Post along with a migration file:
php artisan make:model Post -m
Modify the migration file database/migrations/xxxx_xx_xx_create_posts_table.php
:
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
Run the migration:
php artisan migrate
Define fillable fields in the Post
model (app/Models/Post.php
):
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = ['title', 'content'];
}
Open routes/web.php
and define routes for CRUD operations:
use App\Http\Controllers\PostController;
Route::get('/', [PostController::class, 'index']);
Route::get('/posts', [PostController::class, 'fetchPosts']);
Route::post('/posts', [PostController::class, 'store']);
Route::get('/posts/{id}', [PostController::class, 'edit']);
Route::put('/posts/{id}', [PostController::class, 'update']);
Route::delete('/posts/{id}', [PostController::class, 'destroy']);
Generate a controller for handling requests:
php artisan make:controller PostController
Modify app/Http/Controllers/PostController.php
:
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index()
{
return view('posts.index');
}
public function fetchPosts()
{
return response()->json(Post::all());
}
public function store(Request $request)
{
$post = Post::create($request->all());
return response()->json($post);
}
public function edit($id)
{
return response()->json(Post::find($id));
}
public function update(Request $request, $id)
{
$post = Post::find($id);
$post->update($request->all());
return response()->json($post);
}
public function destroy($id)
{
Post::destroy($id);
return response()->json(['message' => 'Post deleted successfully']);
}
}
Create the view file resources/views/posts/index.blade.php
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Laravel 12 AJAX CRUD</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div class="container mt-5">
<h2 class="text-center">Laravel 12 AJAX CRUD with jQuery & Bootstrap</h2>
<button class="btn btn-primary" id="addPost">Add Post</button>
<table class="table table-bordered mt-3">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Content</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="postTable"></tbody>
</table>
</div>
<!-- Add/Edit Modal -->
<div id="postModal" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Post Form</h5>
</div>
<div class="modal-body">
<input type="hidden" id="postId">
<input type="text" id="title" class="form-control mb-2" placeholder="Title">
<textarea id="content" class="form-control" placeholder="Content"></textarea>
</div>
<div class="modal-footer">
<button class="btn btn-success" id="savePost">Save</button>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function() {
fetchPosts();
function fetchPosts() {
$.get('/posts', function(posts) {
let rows = '';
posts.forEach(post => {
rows += `
<tr>
<td>${post.id}</td>
<td>${post.title}</td>
<td>${post.content}</td>
<td>
<button class="btn btn-warning edit" data-id="${post.id}">Edit</button>
<button class="btn btn-danger delete" data-id="${post.id}">Delete</button>
</td>
</tr>
`;
});
$('#postTable').html(rows);
});
}
$('#addPost').click(function() {
$('#postId').val('');
$('#title').val('');
$('#content').val('');
$('#postModal').modal('show');
});
$('#savePost').click(function() {
let id = $('#postId').val();
let data = { title: $('#title').val(), content: $('#content').val() };
let url = id ? `/posts/${id}` : '/posts';
let method = id ? 'PUT' : 'POST';
$.ajax({ url, method, data, success: function() { fetchPosts(); $('#postModal').modal('hide'); } });
});
$(document).on('click', '.edit', function() {
let id = $(this).data('id');
$.get(`/posts/${id}`, function(post) {
$('#postId').val(post.id);
$('#title').val(post.title);
$('#content').val(post.content);
$('#postModal').modal('show');
});
});
$(document).on('click', '.delete', function() {
let id = $(this).data('id');
$.ajax({ url: `/posts/${id}`, method: 'DELETE', success: function() { fetchPosts(); } });
});
});
</script>
</body>
</html>
This tutorial demonstrated how to implement AJAX CRUD operations in Laravel 12 using jQuery and Bootstrap. With this approach, data operations happen dynamically without reloading the page, providing a better user experience.