Now we will make an editing form. But, differently from the Create form, this time we will make inline editing, so you could edit the category inside the table, without leaving the page.
First, we need a public property to know which category will be edited.
app/Http/Livewire/CategoriesList.php:
class CategoriesList extends Component{ // ... public int $editedCategoryId = 0; }
Next, we will add the wire:click
action to the Edit
button which will receive Category ID and in the component will be set to $editedCategoryId
.
resources/livewire/categories-list.blade.php:
<x-primary-button> <x-primary-button wire:click="editCategory({{ $category->id }})"> Edit</x-primary-button>
app/Livewire/CategoriesList.php:
class CategoriesList extends Component{ // ... public function editCategory(int $categoryId): void { $this->editedCategoryId = $categoryId; $this->category = Category::find($categoryId); $this->name = $this->category->name; $this->slug = $this->category->slug; } // ...}
Now, for the form, when $editedCategoryId
is set, we need to show the inputs, otherwise we show the values as text. For that, we will play with the CSS class hidden
and some if-else statements.
resources/livewire/categories-list.blade.php:
// <td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap"> {{ $category->name }} </td> <td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap"> {{ $category->slug }} </td> {{-- Inline Edit Start --}} <td class="@if($editedCategoryId !== $category->id) hidden @endif px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap"> <x-text-input wire:model.live.debounce="name" id="name" class="py-2 pr-4 pl-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 </td> <td class="@if($editedCategoryId !== $category->id) hidden @endif px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap"> <x-text-input wire:model="slug" id="slug" class="py-2 pr-4 pl-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 </td> {{-- Inline Edit End --}} {{-- Show Category Name/Slug Start --}} <td class="@if($editedCategoryId === $category->id) hidden @endif px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap"> {{ $category->name }} </td> <td class="@if($editedCategoryId === $category->id) hidden @endif px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap"> {{ $category->slug }} </td> {{-- Show Category Name/Slug End --}} //
For buttons, it's very similar, when editing we need to show the Save
and Cancel
buttons, otherwise Edit
and Delete
.
resources/livewire/categories-list.blade.php:
@if($editedCategoryId === $category->id) <x-primary-button wire:click="save"> Save </x-primary-button> <x-primary-button wire:click.prevent="cancelCategoryEdit"> Cancel </x-primary-button>@else <x-primary-button wire:click="editCategory({{ $category->id }})"> Edit </x-primary-button> <button class="px-4 py-2 text-xs text-red-500 uppercase bg-red-200 rounded-md border border-transparent hover:text-red-700 hover:bg-red-300"> Delete </button>@endif
As you can see, when saving, we use the same method save()
. When creating a new category, we must check if the $category
property is null. If it is null, then a new category will be created; otherwise updated.
When saving we need to check if $editedCategoryId
is set, if it is we don't need to set position, and after saving reset $editedCategoryId
.
For cancel, we add a new method cancelCategoryEdit()
where we just need to reset $editedCategoryId
and error bag.
app/Livewire/CategoriesList.php:
class CategoriesList extends Component{ // ... public function save() { $this->validate(); if (is_null($this->category)) { $position = Category::max('position') + 1; Category::create(array_merge($this->only('name', 'slug'), ['position' => $position])); } else { $this->category->update($this->only('name', 'slug')); } $this->reset('showModal'); $this->resetValidation(); $this->reset('showModal', 'editedCategoryId'); } public function cancelCategoryEdit() { $this->resetValidation(); $this->reset('editedCategoryId'); }
After we click Save, the category data is updated both in the DB and in the table visually.
I think that you need to clear the validation messages when you click "Edit" on a different table row, than the one you are editing. Example (gif animation): https://postimg.cc/nMXX50X6
@phuyer, is
cancelCategoryEdit
button working for you?Good point for the validation, updated this lesson and repo.
The
cancelCategoryEdit
button is not working. Also validation bug still presists as mentioned by @phuyer!What's not working for you? As you saw in phuyer animation, the buttons works for him. Validation fixed now.
I've had issue with cancel button as well. If I add prevent the click event, it cancels
Providing each 'x-primary-button' with a unique id works for me.
Same here cancel not working.
for the validation bug reset the validation in the editCategory function :-
@Filimoni Lutunaika I changed that x-primary-button to span tag and that worked
Use hidden class technique just like before. Like this
For classes, at least for me, it's better to use
@class()
Blade directiveCould someone point out the direction to go if I want to use the create modal for editing instead of this inline editing?
Toggle
$showModal
oneditCategory
component's method (which gets called when edit button is clicked) and for end-user's readability change the inner text in the modal's button to "Update" instead of "Create", and the modal title to "Edit Category" when$category
(or$editedCategoryId
, after all one doesn't exists without the other) doesn't have the default "empty" value (for$category
, null).Also make sure to populate the form fields with the category data, and add a
closeModal
method to reset everything when the modal is closed.