You probably have noticed that we have "Active" toggle in the table. Let's implement its behavior, so you could click on that Toggle to change the value immediately, without leaving the table page.
This is the expected result, visually:
You might have seen that in Categories migration we have a column is_active
, so we will change its value in the database.
First, we need a public property in the Livewire Component. It will be an array and called $active
.
app/Livewire/CategoriesList.php:
class CategoriesList extends Component{ use WithPagination; public Category $category; public bool $showModal = false; public array $active = []; //}
Next, we need a list of active categories. For this, we will use a Collections method mapWithKeys().
class CategoriesList extends Component{ // public function render(): View { $categories = Category::paginate(10); $this->active = $categories->mapWithKeys( fn (Category $item) => [$item['id'] => (bool) $item['is_active']] )->toArray(); return view('livewire.categories-list', [ 'categories' => $categories, ]); } //}
This will return the array result of category_id => true/false
:
array:10 [▼ // app/Http/Livewire/CategoriesList.php:50 1 => true 2 => true 3 => true 4 => true 5 => true 6 => true 7 => true 8 => true 9 => true 10 => true]
Now we can bind the toggle button to the active
property and add action to the toggle activity, with this code:
wire:model="active.{{ $category->id }}"wire:click="toggleIsActive({{ $category->id }})"
The full code of the <td>
column:
resources/livewire/categories-list.blade.php:
<td class="px-6"> <div class="inline-block relative mr-2 w-10 align-middle transition duration-200 ease-in select-none"> <input type="checkbox" name="toggle" class="block absolute w-6 h-6 bg-white rounded-full border-4 appearance-none cursor-pointer focus:outline-none toggle-checkbox" /> <label for="toggle" class="block overflow-hidden h-6 bg-gray-300 rounded-full cursor-pointer toggle-label"></label> <input wire:model="active.{{ $category->id }}" wire:click="toggleIsActive({{ $category->id }})" type="checkbox" name="toggle" id="{{ $loop->index.$category->id }}" class="block absolute w-6 h-6 bg-white rounded-full border-4 appearance-none cursor-pointer focus:outline-none toggle-checkbox" /> <label for="{{ $loop->index.$category->id }}" class="block overflow-hidden h-6 bg-gray-300 rounded-full cursor-pointer toggle-label"></label> </div></td>
By default, all categories are active, so you should see all of them marked as active in the table:
To make a button look like a toggle button, we need to add some custom CSS.
resources/css/app.css:
@tailwind base;@tailwind components;@tailwind utilities; .toggle-checkbox:checked { @apply right-0 border-green-400;} .toggle-checkbox:checked + .toggle-label { @apply bg-green-400;}
Next, we will make the button work. In the Blade file, we called the action toggleIsActive
which receives category ID.
app/Livewire/CategoriesList.php:
class CategoriesList extends Component{ // ... public function toggleIsActive(int $categoryId): void { Category::where('id', $categoryId)->update([ 'is_active' => $this->active[$categoryId], ]); } // ...
This method is very simple, we just need to update Category
with the value from the $active
property, calling the specific element.
That's it, our active/inactive Toggle button works!
How can we apply a newer @checked blade directive?
I don't think we can apply it here.
Getting Error
Attempt to read property "index" on null
I thank something is missing, but What, and where should it be?
Why are we creating an in-memory dictionary (an associative array with same structure for all key-value pairs) to hold the value from each category's
is_active
property?Couldn't we just bind the toggling to the
is_active
of the current iterated$category
inside the loop?I did that and got the same result, with more performance and readability: the
active
array does not need to be recreated on every update in$categories
; thetoggleIsActive
receives as argument the$category
itself rather than its id (thus no need to fetch it in the database: we just update it directly).e.g: