Courses

Practical Livewire 3: Order Management System Step-by-Step

Create New Category Modal

Now let's create a real dynamic thing with Livewire: a Modal to show the form to create a category.

create category modal

Also, we will make the Slug field automatically generated after we change the Name field.

First, we will add the modal itself with form. In the resources/livewire/categories-list.blade.php just before last </div>, add this code:

//
<div class="@if (!$showModal) hidden @endif flex items-center justify-center fixed left-0 bottom-0 w-full h-full bg-gray-800 bg-opacity-90">
<div class="w-1/2 bg-white rounded-lg">
<form wire:submit.prevent="save" class="w-full">
<div class="flex flex-col items-start p-4">
<div class="flex items-center pb-4 mb-4 w-full border-b">
<div class="text-lg font-medium text-gray-900">Create Category</div>
<svg wire:click.prevent="$set('showModal', false)"
class="ml-auto w-6 h-6 text-gray-700 cursor-pointer fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18">
<path d="M14.53 4.53l-1.06-1.06L9 7.94 4.53 3.47 3.47 4.53 7.94 9l-4.47 4.47 1.06 1.06L9 10.06l4.47 4.47 1.06-1.06L10.06 9z" />
</svg>
</div>
<div class="mb-2 w-full">
<label class="block text-sm font-medium text-gray-700" for="name">
Name
</label>
<input wire:model.live.debounce="name" id="name"
class="py-2 pr-4 pl-2 mt-2 w-full text-sm rounded-lg border border-gray-400 sm:text-base focus:outline-none focus:border-blue-400" />
@error('name')
<span class="text-sm text-red-500">{{ $message }}</span>
@enderror
</div>
<div class="mb-2 w-full">
<label class="block text-sm font-medium text-gray-700" for="slug">
Slug
</label>
<input wire:model="slug" id="slug"
class="py-2 pr-4 pl-2 mt-2 w-full text-sm rounded-lg border border-gray-400 sm:text-base focus:outline-none focus:border-blue-400" />
@error('slug')
<span class="text-sm text-red-500">{{ $message }}</span>
@enderror
</div>
<div class="mt-4 ml-auto">
<button class="px-4 py-2 font-bold text-white bg-blue-500 rounded hover:bg-blue-700" type="submit">
Create
</button>
<button wire:click="$set('showModal', false)" class="px-4 py-2 font-bold text-white bg-gray-500 rounded" type="button" data-dismiss="modal">
Close
</button>
</div>
</div>
</form>
</div>
</div>
 
</div>

As you can see, in the modal we have the $showModal variable and binded form inputs to name and slug. In the CategoriesList component, we need to add public properties for them.

app/Livewire/CategoriesList.php:

class CategoriesList extends Component
{
use WithPagination;
 
public ?Category $category = null;
 
public string $name = '';
public string $slug = '';
 
public bool $showModal = false;
 
public function render(): View
{
$categories = Category::paginate(10);
 
return view('livewire.categories-list', [
'categories' => $categories,
]);
}
}

To open the modal, first, add the wire:click action to the Add Category button.

resources/livewire/categories-list.blade.php:

<x-primary-button wire:click="openModal" type="button" class="mb-4">
Add Category
</x-primary-button>

When the button is clicked, the openModal method in the Livewire component will be called. In this method, we set $showModal to true.

app/Livewire/CategoriesList.php:

class CategoriesList extends Component
{
use WithPagination;
 
public Category $category;
 
public bool $showModal = false;
 
public function openModal(): void
{
$this->showModal = true;
}
 
public function render(): View
{
$categories = Category::paginate(10);
 
return view('livewire.categories-list', [
'categories' => $categories,
]);
}
}

Now, after clicking Add Category, you will see the modal with the form.

create category modal

Before creating a category, let's add validation to the form. For this, we will use the rules() method in the Livewire component.

class CategoriesList extends Component
{
use WithPagination;
 
// ...
 
protected function rules(): array
{
return [
'name' => ['required', 'string', 'min:3'],
'slug' => ['nullable', 'string'],
];
}
}

For the slug field, we will generate it automatically from the name. To achieve this, we will use Livewire Lifecycle Hooks.

app/Http/Livewire/CategoriesList.php:

use Illuminate\Support\Str;
 
class CategoriesList extends Component
{
use WithPagination;
 
// ...
 
public function updatedName(): void
{
$this->slug = Str::slug($this->name);
}
 
// ...
}

create category form with auto slug

Now, saving the category.

In the form we added a Livewire Action wire:submit="save", which means when the Create button is pressed, the save() method in Livewire Component will be called.

class CategoriesList extends Component
{
// ...
 
public function save()
{
$this->validate();
 
Category::create($this->only('name', 'slug'));
 
$this->reset('showModal');
}
}

Here, we first validate and then save the category to the DB. After that, we set the $showModal to its initial value which is false.

A new category is created successfully, yay!

new category created

Previous: Categories Table with Livewire
avatar

thank you for this page

avatar
You can use Markdown
avatar

The add category button does not show modal on click in laravel 10.

avatar

Are there any errors in your browser console? No one else reported such bug.

avatar

There no errors on the browser console

avatar

Also need repo to see your code

avatar

Sorry for the necro... I got same problem with Livewire: Multiple root elements detected.

The problem is that the modal's div was outside the main div, after moving it inside, everything worked as expected.

PS. I am using laravel 10

avatar

Its just how livewire works.

avatar

PS Don't forget to have a cmd with "npm run dev" running if you are on Laravel 10. That was the problem for me with the modal not showing.

avatar
You can use Markdown
avatar

About postions: One should create the postions in numerical order, else moving a post with drag and drop won't work properly. So, move the creation of categories from the Categoryseeder (delete it) into the Databaseseeder:

$position = 1;
while ($position < 13){
		Category::factory()->create(['position' => $position,]);
		$position ++;
}
avatar
You can use Markdown
avatar
Ikaro Campos Laborda

livewire.js?id=a27c4ca2:347 Uncaught TypeError: Cannot read properties of null (reading 'name') at livewire.js?id=a27c4ca2:347:19 at Array.reduce (

It seems that in the latest version of Livewire, the binding category.name is not working as it works in this course. struggling to find a solution.

avatar

Its because you are using the old syntax. Properties can't be binded to model directly

avatar
Ikaro Campos Laborda

How do I fix that?

avatar

Read the docs. You can enable the old syntax but it is not recommended. This course was made when v3 wasn't released.

avatar
You can use Markdown
avatar
You can use Markdown