I am working on a Laravel 10 site. Using docs at https://dev.to/koossaayy/laravel-livewire-multiple-selection-with-virtual-select-1f87, I try to make multiselection. I made it with some changes in the code.
In component:
<?php
namespace App\Livewire\Admin;
use App\Models\Permission;
use Illuminate\Support\Str;
use Livewire\Component;
class UsersPermissionsEditor extends Component
{
public $selectedPermissions= [];
public $permissionsListing= [];
public function render()
{
$this->permissionsListing = Permission::query()->get()/*->pluck('name', 'id')*/
->map(function ($selectedPermissionItem) {
return ['id' => $selectedPermissionItem->id, 'label' => Str::replace('_', ' ', Str::title($selectedPermissionItem->name))];
})
->toArray();
return view('livewire.admin.users-permissions-editor');
}
}
and in Blade:
<div class="admin_page_container" id="users_permissions_editor_admin_page_container">
<div class="editor_listing_wrapper_bix_width" x-data="adminUsersPermissionsEditorComponent()"
x-init="[onAdminUsersPermissionsEditorComponentInit() ]" x-cloak>
$selectedPermissions::{{ print_r($selectedPermissions, true) }}
<input id="permissionsListing" name="permissionsListing" value="add permissionsListing TEST">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/virtual-select.min.js"
integrity="sha256-Gsn2XyJGdUeHy0r4gaP1mJy1JkLiIWY6g6hJhV5UrIw=" crossorigin="anonymous"></script>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/virtual-select.min.css"
integrity="sha256-KqTuc/vUgQsb5EMyyxWf62qYinMUXDpWELyNx+cCUr0=" crossorigin="anonymous">
<div>
AAAAA<div id="permissions"></div>BBB
<script>
function adminUsersPermissionsEditorComponent() {
console.log('adminUsersPermissionsEditorComponent::')
return {
fillUsersPermissions: function () {
var permissionsListing = @json($permissionsListing)
VirtualSelect.init({
ele: '#permissions',
multiple: true,
options: permissionsListing,
});
let selectedPermissions = document.querySelector('#permissions');
selectedPermissions.addEventListener('change', () => {
let data = selectedPermissions.value;
@this.set('selectedPermissions', data);
});
},
onAdminUsersPermissionsEditorComponentInit: function () {
},
}
}
</script>
</div>
</div>
I see available multiselection element, but when I click on one of elements the multiselection element is not visible at all.
What I see in browsers console:
How that can be fixed?
"laravel/framework": "^10.48.4",
"livewire/livewire": "^3.4.9",
The main problem is that every time @this.set('selectedPermissions',.... is applied a call to the backend is done, so the DOM is redrawn and the changes and the event listeners applied by VirtualSelect are lost.
A simple fix is to add a wire:ignore to the <div> used by VirtualSelect, in this way Livewire will not alter the content of that <div>:
class UsersPermissionsEditor extends Component
{
public $selectedPermissions = [1, 3];
public $permissionsListing = [];
public function render()
{
$this->permissionsListing = Permission::query()
->get(['id', 'name'])
->map(function ($selectedPermissionItem) {
return ['value' => $selectedPermissionItem->id,
'label' => Str::replace('_', ' ', Str::title($selectedPermissionItem->name))
];
})->toArray();
return view('livewire.admin.users-permissions-editor');
}
}
<div class="admin_page_container" id="users_permissions_editor_admin_page_container">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/virtual-select.min.js"
integrity="sha256-Gsn2XyJGdUeHy0r4gaP1mJy1JkLiIWY6g6hJhV5UrIw=" crossorigin="anonymous">
</script>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/virtual-select.min.css"
integrity="sha256-KqTuc/vUgQsb5EMyyxWf62qYinMUXDpWELyNx+cCUr0=" crossorigin="anonymous"
>
<div class="editor_listing_wrapper_bix_width"
x-data="adminUsersPermissionsEditorComponent('permissions')"
x-cloak
>
<div>
<div wire:ignore id="permissions"></div>
</div>
</div>
selectedPermissions: {{ implode(', ', $selectedPermissions) }}
</div>
<script>
function adminUsersPermissionsEditorComponent(element) {
return {
init: function () {
VirtualSelect.init({
ele: "#" + element,
multiple: true,
options: @json($permissionsListing),
selectedValue: @json($selectedPermissions)
});
document.getElementById(element).addEventListener("change", function () {
// console.log (this.value);
@this.set("selectedPermissions", this.value);
});
},
}
}
</script>
In this example I've applied some changes: