How to Create a CRUD Using Laravel Livewire?

This is a simple step by step guide that will help us understand how we can create a CRUD with the help of Laravel Livewire. Anyone can easily learn through this tutorial and implement changes in his own Laravel projects Laravel projects using Livewire.

We will create a Livewire CRUD application to demonstrate the ease and power of Livewire. After creating new Laravel application and updating .env file to configure Database, lets run this composer command:

composer require livewire/livewire

This will install Laravel Livewire package which is ready to us to use. Then we will create a new model.

php artisan make:model Category -m

that “-m” will create migration along with model for us. In that migration, we will write this code in “up()” method.

public function up()
{
    Schema::create('categories', function (Blueprint $table) {
        $table->id();
        $table->string('name')->nullable();
        $table->text('description')->nullable();
        $table->timestamps();
    });
}

Then we will run migrate command to create “categories” table in the database.

php artisan migrate

Now this code will go in our “Category” model which you will find in “app/Models” folder.

namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
    use HasFactory;
    protected $fillable = [
        'name', 'description'
    ];
    public $timestamps = true;
}

Now this is something new. In order to create both Livewire controller and view, we need to run a simple command.

php artisan make:livewire category

After running this command you will find two files in the following path

app/Http/Livewire/Category.php and resources/views/livewire/category.blade.php

Now in “Category.php” file we will write this code. /

namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\Category as Categories;
class Category extends Component
{
    public $categories, $name, $description, $category_id;
    public $updateCategory = false;
    protected $listeners = [
        'deleteCategory'=>'destroy'
    ];
    // Validation Rules
    protected $rules = [
        'name'=>'required',
        'description'=>'required'
    ];
    public function render()
    {
        $this->categories = Categories::select('id','name','description')->get();
        return view('livewire.category');
    }
    public function resetFields(){
        $this->name = '';
        $this->description = '';
    }
    public function store(){
        // Validate Form Request
        $this->validate();
        try{
            // Create Category
            Categories::create([
                'name'=>$this->name,
                'description'=>$this->description
            ]);
    
            // Set Flash Message
            session()->flash('success','Category Created Successfully!!');
            // Reset Form Fields After Creating Category
            $this->resetFields();
        }catch(\Exception $e){
            // Set Flash Message
            session()->flash('error','Something goes wrong while creating category!!');
            // Reset Form Fields After Creating Category
            $this->resetFields();
        }
    }
    public function edit($id){
        $category = Categories::findOrFail($id);
        $this->name = $category->name;
        $this->description = $category->description;
        $this->category_id = $category->id;
        $this->updateCategory = true;
    }
    public function cancel()
    {
        $this->updateCategory = false;
        $this->resetFields();
    }
    public function update(){
        // Validate request
        $this->validate();
        try{
            // Update category
            Categories::find($this->category_id)->fill([
                'name'=>$this->name,
                'description'=>$this->description
            ])->save();
            session()->flash('success','Category Updated Successfully!!');
    
            $this->cancel();
        }catch(\Exception $e){
            session()->flash('error','Something goes wrong while updating category!!');
            $this->cancel();
        }
    }
    public function destroy($id){
        try{
            Categories::find($id)->delete();
            session()->flash('success',"Category Deleted Successfully!!");
        }catch(\Exception $e){
            session()->flash('error',"Something goes wrong while deleting category!!");
        }
    }
}

Now in order to use this newly build Livewire component, we just to add this code anywhere in our blade file.

@livewire('category')

We will put this code in our “home.blad.php” file like this.

<!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>Livewire Crud Example - Laramatic</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
    @livewireStyles
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container-fluid">
            <a class="navbar-brand" href="/">Livewire Crud Example - Laramatic</a>
        </div>
    </nav>
    <div class="container">
        <div class="row justify-content-center mt-3">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header text-center">
                        <h2>Livewire Crud Example - Laramatic</h2>
                        <a href="https://laramatic.com" target="_blank">Visit Site</a>
                    </div>
                </div>
            </div>
        </div>
        <div class="row justify-content-center mt-3">
            @livewire('category')
        </div>
    </div>
    
    @livewireScripts
</body>
</html>

and then in our “category.blade.php” file we will put this code.

<div>
    <div class="col-md-8 mb-2">
        <div class="card">
            <div class="card-body">
                @if(session()->has('success'))
                    <div class="alert alert-success" role="alert">
                        {{ session()->get('success') }}
                    </div>
                @endif
                @if(session()->has('error'))
                    <div class="alert alert-danger" role="alert">
                        {{ session()->get('error') }}
                    </div>
                @endif
                @if($updateCategory)
                    @include('livewire.update')
                @else
                    @include('livewire.create')
                @endif
            </div>
        </div>
    </div>
    <div class="col-md-8">
        <div class="card">
            <div class="card-body">
                <div class="table-responsive">
                    <table class="table">
                        <thead>
                            <tr>
                                <th>Name</th>
                                <th>Description</th>
                                <th>Action</th>
                            </tr>
                        </thead>
                        <tbody>
                            @if (count($categories) > 0)
                                @foreach ($categories as $category)
                                    <tr>
                                        <td>
                                            {{$category->name}}
                                        </td>
                                        <td>
                                            {{$category->description}}
                                        </td>
                                        <td>
                                            <button wire:click="edit({{$category->id}})" class="btn btn-primary btn-sm">Edit</button>
                                            <button onclick="deleteCategory({{$category->id}})" class="btn btn-danger btn-sm">Delete</button>
                                        </td>
                                    </tr>
                                @endforeach
                            @else
                                <tr>
                                    <td colspan="3" align="center">
                                        No Categories Found.
                                    </td>
                                </tr>
                            @endif
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
    <script>
        function deleteCategory(id){
            if(confirm("Are you sure to delete this record?"))
                window.livewire.emit('deleteCategory',id);
        }
    </script>
</div>

Then we will create a new file in same folder with the name of “create.blade.php” and paste this code in that file.

<form>
    <div class="form-group mb-3">
        <label for="categoryName">Name:</label>
        <input type="text" class="form-control @error('name') is-invalid @enderror" id="categoryName" placeholder="Enter Name" wire:model="name">
        @error('name') <span class="text-danger">{{ $message }}</span>@enderror
    </div>
    <div class="form-group mb-3">
        <label for="categoryDescription">Description:</label>
        <textarea class="form-control @error('description') is-invalid @enderror" id="categoryDescription" wire:model="description" placeholder="Enter Description"></textarea>
        @error('description') <span class="text-danger">{{ $message }}</span>@enderror
    </div>
    <div class="d-grid gap-2">
        <button wire:click.prevent="store()" class="btn btn-success btn-block">Save</button>
    </div>
</form>

Then we need to create a new file “update.blade.php” in the same folder and we will write this code in that file.

<form>
    <input type="hidden" wire:model="category_id">
    <div class="form-group mb-3">
        <label for="categoryName">Name:</label>
        <input type="text" class="form-control @error('name') is-invalid @enderror" id="categoryName" placeholder="Enter Name" wire:model="name">
        @error('name') <span class="text-danger">{{ $message }}</span>@enderror
    </div>
    <div class="form-group mb-3">
        <label for="categoryDescription">Description:</label>
        <textarea class="form-control @error('description') is-invalid @enderror" id="categoryDescription" wire:model="description" placeholder="Enter Description"></textarea>
        @error('description') <span class="text-danger">{{ $message }}</span>@enderror
    </div>
    <div class="d-grid gap-2">
        <button wire:click.prevent="update()" class="btn btn-success btn-block">Save</button>
        <button wire:click.prevent="cancel()" class="btn btn-danger">Cancel</button>
    </div>
</form>

Then we will just need to create a route to our home.blade.php view and we are good to go.

Route::get('/',function(){
    return view('home');
});

If you have any questions please write down in comments section. Your feedback and questions means a lot to us.