In this tutorial, we will create an iOS looking like toggle switch button that saves its state in our database using Livewire and Tailwind for styling. We will make our Livewire component reusable so we don’t have to create another component when we want to use the button somewhere else in the application. I’ll show you how to pass ‘data’ dynamically and hydrate your Livewire component ‘on the fly’.
First we create our Livewire component
php artisan livewire:make ToggleButton
Now we have two files. The ToggleButton.php in app/Http/livewire/ and toggle-button.blade.php in resources/views/livewire.
Let’s get the toggle button styled with tailwind from TailwindComponents.
<style>
/* CHECKBOX TOGGLE SWITCH */
/* @apply rules for documentation, these do not work as inline style */
.toggle-checkbox:checked {
@apply: right-0 border-green-400;
right: 0;
border-color: #68D391;
}
.toggle-checkbox:checked + .toggle-label {
@apply: bg-green-400;
background-color: #68D391;
}
</style>
<div class="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
<input type="checkbox" name="toggle" id="toggle" class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer"/>
<label for="toggle" class="toggle-label block overflow-hidden h-6 rounded-full bg-gray-300 cursor-pointer"></label>
</div>
Now in our markup, we will want to bind the “hasStock” (you can use isActive or anything related to your project). So the input tag will look like this:
<input wire:model="hasStock" type="checkbox" name="toggle" id="toggle" class="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer"/>
Now let’s go and create the logic we need in order to make this work (you should have a “stock” field in your database for your model).
<?php
namespace App\Http\Livewire;
use Illuminate\Database\Eloquent\Model;
use Livewire\Component;
class ToggleButton extends Component
{
public Model $model;
public string $field;
public bool $hasStock;
public function mount()
{
$this->hasStock = (bool) $this->model->getAttribute($this->field);
}
public function render()
{
return view('livewire.toggle-button');
}
public function updating($field, $value)
{
$this->model->setAttribute($this->field, $value)->save();
}
}
In our Livewire component, we don’t want to hardcode the model name and we want to make this component reusable within the project. Therefore, we declared public Model $model which will expect to return an instance of Illuminate\Database\Eloquent\Model. In our case, we will pass the instance as a property of the component in our view.
The component is pretty simple, we have a $model and a $field that matches our database ($product->stock) and we will get these values from our blade view when rendering the component.
Let’s say we render this component on a typical laravel blade view (products.blade.php). So here’s an example of this view:
@foreach($products as $product)
<div>
<livewire:toggle-button
:model="$product"
field="stock"
key="{{ $product->id }}" />
</div>
@endforeach
Since in this view we already have access to the Products::class we can pass and hydrate the $model->field by binding :model to an instance of the model and field as a corresponding field of that model. As you noticed already, we also passed a key to our toggle button. Livewire has no way of keeping track of which button is which and to avoid any unexpected behaviour we set the key to equal the $product->id which is unique.
That’s it. You should now have a fully functional switch button that saves the boolean value of the switch in the database. Here’s a quick demo of how the toggle switch button is working in an app that I’m building at the moment.
Originally posted on LaravelMagazine
Top comments (4)
Could I get some help, I can't seem to pass the row id to the component. The data being passed are all NULL.
Finally it's asking to insert instead of update
data:
model:
view:
component:
Hi, I've applied your tutorial on my laravel livewire project, and it's working, but it's messing with the table pagination : I cannot go to the table page 2, etc. I have this error message in the browser console :
Thanks loads for this...works like a charm
Hi
what if I want to bind it to an extra field in a pivot table?