DEV Community

Cover image for Laravel Livewire Multiple Selection with Virtual Select
Koussay
Koussay

Posted on • Updated on

Laravel Livewire Multiple Selection with Virtual Select

Hello.
Recently in of our projects, we had to create a multiple selection dropdown. We were using Livewire, and vanilla JavaScript (no AlpineJS), so the options were either using the default multiple select, which is to be honest, ugly.
So we have to check for something else. The next options was Select2 Js, a popular jQuery library.
The problem with Select2 was the jQuery, we have to import jQuery just for that, and also the design wasn't that good actually.

So after little research, and so many thanks for skywalker , we were introduced to Virtual Select.

What we like about Virtual Select is the looks and the performance of it. It was amazing really, no dependencies and it worked from the first try.
Unfortunately, the plugin doesn't support ES6 yet.
But if you want to contribute, here is the link to issue discussing the matter.

In this tutorial we will cover how to import Virtual Select, and how to retrieve data in our component.

NOTE: : This tutorial will assume you have a Laravel installation in place already and Livewire is also installed.

NOTE: : In this tutorial we will not cover how to get data from API, it maybe for another tutorial soon 🤞.

That being said, the first thing to do is to create the Livewire component. A common use case for this would be as follows:
Select multiple permissions for a specific user.
So our component would be named, for example EditUser.
So run this in your terminal :

php artisan livewire:make EditUser 
Enter fullscreen mode Exit fullscreen mode

After creating the component, the next thing to do is open the class, called EditUser.php, and edit the render method as follows :

use App\Models\Permission;
use Livewire\Component;

class EditUser extends Component
{
    public function render()
    {
        $permissions = Permission::query()->get();
        return view('livewire.edit-user')->with('permissions', $permissions);
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, we added the list of permissions needed to assign them to the desired user.
Another thing to do here, is to prepare a public property to hold those assigned permissions. So the class will be as follows :

use App\Models\Permission;
use Livewire\Component;

class EditUser extends Component
{

    public $selectedPermissions= [];


    public function render()
    {
        $permissions = Permission::query()->get();
        return view('livewire.edit-user')->with('permissions', $permissions);
    }
}
Enter fullscreen mode Exit fullscreen mode

And of course your component would hold other properties such as the user property and other stuff, but for the sake of this tutorial, we are making it simple.

Anyways, moving on now to the frontend. The first thing you need to do is to "import" Virtual Select CSS & JS assets.
You can download them, or use a CDN.
For this example, we will use jsdelivr.com .
So the first thing you need, is to use them in your main layout file as follows:

    <script src="https://cdn.jsdelivr.net/npm/virtual-select-plugin@1.0.39/dist/virtual-select.min.js" integrity="sha256-Gsn2XyJGdUeHy0r4gaP1mJy1JkLiIWY6g6hJhV5UrIw=" crossorigin="anonymous"></script>

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/virtual-select-plugin@1.0.39/dist/virtual-select.min.css" integrity="sha256-KqTuc/vUgQsb5EMyyxWf62qYinMUXDpWELyNx+cCUr0=" crossorigin="anonymous">
Enter fullscreen mode Exit fullscreen mode

Also, you may want to use @stack for the JavaScript we will use in the component later.
After those modifications, our main layout file would be look like this

...
    @livewireStyles
    <script src="https://cdn.jsdelivr.net/npm/virtual-select-plugin@1.0.39/dist/virtual-select.min.js" integrity="sha256-Gsn2XyJGdUeHy0r4gaP1mJy1JkLiIWY6g6hJhV5UrIw=" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/virtual-select-plugin@1.0.39/dist/virtual-select.min.css" integrity="sha256-KqTuc/vUgQsb5EMyyxWf62qYinMUXDpWELyNx+cCUr0=" crossorigin="anonymous">
</head>

<body>




    @livewireScripts
    @stack('js')
    ...
</body>
...
Enter fullscreen mode Exit fullscreen mode

Now moving on to our component.
The first thing to do is to initiate an empty div for the plugin to work. So open edit-user.blade.php and add the empty div with an id so we can reference it later.
At first, our component will look like this :

<div>
    <div id="permissions"></div>
</div>
Enter fullscreen mode Exit fullscreen mode

After initializing the DOM element, the next thing to do is to initiate the plugin. In order to do so, we will "push" the stacked js we defined earlier. It will look like this :

<div>
    <div id="permissions"></div>
    @push('js')
        <script>

        </script>
    @endpush
</div>
Enter fullscreen mode Exit fullscreen mode

And now let's get to work. We need to define our options, to do so, we can create a new JavaScript variable to hold the permissions coming from the database.

            const permissions = [
                @foreach ($permissions as $permission)
                    {
                        label: "{{ $permission->name }}",
                        value: "{{ $permission->id }}"
                    },
                @endforeach
            ];

Enter fullscreen mode Exit fullscreen mode

This piece of code, will be able to transform the collection of permissions into a JavaScript array.
After that, what we need to do is to initiate the plugin itself.

<div>
    <div id="permissions"></div>
    @push('js')
        <script>
            const permissions = [
                @foreach ($permissions as $permission)
                    {
                        label: "{{ $permission->name }}",
                        value: "{{ $permission->id }}"
                    },
                @endforeach
            ];
            VirtualSelect.init({
                ele: '#permissions',
                multiple: true,
                options: permissions,
            });
        </script>
    @endpush
</div>
Enter fullscreen mode Exit fullscreen mode

As you can see, we called the init method with the options :

  • ele : The element of the DOM that will render the dropdown

  • multiple : whether to indicate it's a multiple selection or not

  • options : the data the dropdown will populated with, which we defined earlier.
  • At this moment, if we visit the page, our component will be like this:

    At this stage, everything is working perfectly, but the problem is how to tell Livewire about those selections. At this point, we will use Livewire beauty ❤️

    In order to pass the data to Livewire, we will use the JavaScript event listener, whenever the selection is changed, we will send them to our component.
    So in our view file, what we need to add is the following code

                let selectedPermissions = document.querySelector('#permissions');
                selectedPermissions.addEventListener('change', () => {
                    let data = selectedPermissions.value;
                    @this.set('selectedPermissions', data);
                });
    
    
    Enter fullscreen mode Exit fullscreen mode

    What we did is we first get the DOM element defined earlier, then we attach to it an event listener, whenever the selection changes, we want to get the selection and send it to our component.
    And then at the component level, the selected data will be available at $selectedPermissions property, so you can assign them to the user.

    I hope you liked this tutorial, and you gain information about it.
    If something is not clear or you want ask about further information, you can contact me on Twitter or comment down below.
    Thank you again and have a nice day.

    Original Post
    Credits : Photo by Edu Grande on Unsplash

    Top comments (2)

    Collapse
     
    minhazulislam18 profile image
    Minhazul Islam

    After adding this,

    let selectedPermissions = document.querySelector('#permissions');
    selectedPermissions.addEventListener('change', () => {
    let data = selectedPermissions.value;
    @this.set('selectedPermissions', data);
    });
    When I click to select any, it automattically closes! and the full page is no longer clickable!