DEV Community

Cover image for Create a toggle switch in Laravel with Livewire & Tailwind
Marian Pop 🦄
Marian Pop 🦄

Posted on

Create a toggle switch in Laravel with Livewire & Tailwind

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


Enter fullscreen mode Exit fullscreen mode

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>


Enter fullscreen mode Exit fullscreen mode

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"/>


Enter fullscreen mode Exit fullscreen mode

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();
      }
}


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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.

Toggle Button

Originally posted on LaravelMagazine

Top comments (4)

Collapse
 
aspiess profile image
Aron Spiess • Edited

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:

 #content: "{"id":"2UnpKYzKmHAjM1AB2auH","data":{"field":null,"hasStock":false},"name":"toggle-button","checksum":"0a9757b5807b1d5c1eb9ac1c0170fa237b4ddf595ac372bc311a229c2 "
Enter fullscreen mode Exit fullscreen mode

model:

      public function mount(Model $model)
      {
          $this->hasStock = (bool) $model->getAttribute($this->field);
      }
Enter fullscreen mode Exit fullscreen mode

view:

         <livewire:toggle-button
          field="stock{{ $person->id }}"
          key="{{ $person->id }}"/>
Enter fullscreen mode Exit fullscreen mode

component:

      public function updating( $field, $value)
      {

        dump(request(),$field, $value);

        //$model = new \App\CauseSignupsModel;
        //$model->setAttribute($field, $value)->update();
      }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
chazkame profile image
chazkame

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 :

index.js:34 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'fingerprint')

Collapse
 
redamakarem profile image
redamakarem

Thanks loads for this...works like a charm

Collapse
 
aghorbanmehr profile image
aghorbanmehr

Hi
what if I want to bind it to an extra field in a pivot table?