Laravel, a popular PHP framework, has continually evolved to simplify web development. One of its most versatile features is Livewire, a real-time framework that enables seamless interaction between the server and client without writing JavaScript code. In this tutorial, we’ll explore how to implement CRUD (Create, Read, Update, Delete) operations using Livewire in Laravel 10 to create a dynamic and engaging blog post management system.
What is Livewire?
Livewire is a powerful technology that facilitates real-time interaction between a web server and client-side interfaces without the need for writing extensive JavaScript code. Developed specifically for the Laravel PHP framework, Livewire simplifies the creation of dynamic, interactive web applications by allowing developers to build rich user experiences using server-rendered HTML.
Setting Up Your Development Environment
Before diving into Livewire and CRUD operations, ensure you have Laravel 10 installed. If not, use Composer to create a new Laravel project
composer create-project laravel/laravel laravel-liwewire-blog
Navigate to the newly created project directory
cd laravel-liwewire-blog
Installing and Configuring Livewire
composer require livewire/livewire
Publishing the configuration file
php artisan livewire:publish --config
Need to call the JavaScript on every page of our application that will be using Livewire.
Create a layouts
directory and then create a file named as app.blade.php
and add the following code.
<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ $title ?? 'Page Title' }}</title> </head> @livewireStyles </head> <body> {{ $slot }} @livewireScripts <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script> </body> </html>
Creating the Blog Post Model and Migration
Generate a new model and migration for your blog posts
php artisan make:migration create_posts_table php artisan make:model POST
update post migration
<?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(); $table->string('title')->nullable(); $table->text('description')->nullable(); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('posts'); } };
Run the migration to create the table
php artisan migrate
Creating Livewire Components
Now, let’s create the Livewire components needed for the CRUD operations
php artisan make:livewire post
This command will output like this
COMPONENT CREATED 🤙
CLASS: app/Http/Livewire//Post.php
VIEW: C:\xampp\htdocs\laravel-liwewire-blog\resources\views/livewire/post.blade.php
Open the Livewire Post container that we created using the above command and update with this code.
<?php namespace App\Http\Livewire; use Livewire\Component; use App\Models\Post as Posts; class Post extends Component { public $posts, $title, $content, $postId, $updatePost = false, $addPost = false; /** * delete action listener */ protected $listeners = [ 'deletePostListner'=>'deletePost' ]; /** * List of add/edit form rules */ protected $rules = [ 'title' => 'required', 'content' => 'required' ]; /** * Resetting all inputted fields * @return void */ public function resetFields(){ $this->title = ''; $this->content = ''; } /** * Render the post data * @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View */ public function render() { $this->posts = Posts::select('id', 'title', 'content')->get(); return view('livewire.post'); } /** * Open Create Post form * @return void */ public function addPost() { $this->resetFields(); $this->addPost = true; $this->updatePost = false; } /** * store the post data in the posts table * @return void */ public function storePost() { $this->validate(); try { Posts::create([ 'title' => $this->title, 'content' => $this->content ]); session()->flash('success','Post Created Successfully!!'); $this->resetFields(); $this->addPost = false; } catch (\Exception $ex) { session()->flash('error','Something goes wrong!!'); } } /** * show selected post data in edit post form * @param mixed $id * @return void */ public function editPost($id){ try { $post = Posts::findOrFail($id); if( !$post) { session()->flash('error','Post not found'); } else { $this->title = $post->title; $this->content = $post->content; $this->postId = $post->id; $this->updatePost = true; $this->addPost = false; } } catch (\Exception $ex) { session()->flash('error','Something goes wrong!!'); } } /** * update post data * @return void */ public function updatePost() { $this->validate(); try { Posts::whereId($this->postId)->update([ 'title' => $this->title, 'content' => $this->content ]); session()->flash('success','Post Updated Successfully!!'); $this->resetFields(); $this->updatePost = false; } catch (\Exception $ex) { session()->flash('success','Something goes wrong!!'); } } /** * Cancel Add/Edit form and redirect to post listing page * @return void */ public function cancelPost() { $this->addPost = false; $this->updatePost = false; $this->resetFields(); } /** * delete selected post data from the posts table * @param mixed $id * @return void */ public function deletePost($id) { try{ Posts::find($id)->delete(); session()->flash('success',"Post Deleted Successfully!"); }catch(\Exception $e){ session()->flash('error',"Something went wrong!!"); } } }
Now create 3 new files.
post.blade.php
inside resources/views/livewire
create.blade.php
inside resources/views/livewire
update.blade.php
inside resources/views/livewire
Open welcome.blade.php
and update this code.
<!DOCTYPE html> <html lang="en"> <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"> <title>Laravel Livewire Blog</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous"> @livewireStyles </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container-fluid"> <a class="navbar-brand" href="/">Laravel Livewire Blog</a> </div> </nav> <div class="container"> <div class="row justify-content-center mt-3"> @livewire('post') </div> </div> @livewireScripts </body> </html>
Open create.blade.php
add this code.
<form> <div class="form-group"> <label for="title">Title</label> <input type="text" class="form-control @error('title') is-invalid @enderror" id="title" placeholder="Enter Title" wire:model="title"> @error('title') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="form-group"> <label for="content">Content</label> <textarea class="form-control @error('content') is-invalid @enderror" id="content" wire:model="content" placeholder="Enter content"></textarea> @error('content') <span class="text-danger">{{ $message }}</span> @enderror </div> <div> <button wire:click.prevent="storePost()" class="btn btn-success btn-block">Save</button> <button wire:click.prevent="cancelPost()" class="btn btn-secondary btn-block">Cancel</button> </div> </form>
Open update.blade.php
and add this code.
<form> <div class="form-group"> <label for="title">Title</label> <input type="text" class="form-control @error('title') is-invalid @enderror" id="title" placeholder="Enter Title" wire:model="title"> @error('title') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="form-group"> <label for="content">Content</label> <textarea class="form-control @error('content') is-invalid @enderror" id="content" wire:model="content" placeholder="Enter content"></textarea> @error('content') <span class="text-danger">{{ $message }}</span> @enderror </div> <div> <button wire:click.prevent="updatePost()" class="btn btn-success btn-block">Update</button> <button wire:click.prevent="cancelPost()" class="btn btn-secondary btn-block">Cancel</button> </div> </form>
Testing Your Implementation
php artisan serve
Visit the provided URL in your browser and navigate to the page where you’ve included the Livewire components. You should now have a functional blog post management system with CRUD operations using Livewire in Laravel 10.