Current status - needs more info but bulk written
Select2 - Do not use this
- Jquery dependency
- Causes error and lag when many on screen
- Hidden errors see firefox debug
– If you need this working please comment and will post how
Choice.js (https://github.com/jshjohnson/Choices)
- Does not require wire:ignore
- No errors
- No lag
- No jquery dependency
- ES6
I will now show you how to get Choice.js working in livewire with alpine.js:
Let’s start by making a Laravel component
php artisan make:component input/select
Add the following code to the new component:
<div
x-data
x-init="() => {
var choices = new Choices($refs.{{ $attributes['prettyname'] }}, {
itemSelectText: '',
});
choices.passedElement.element.addEventListener(
'change',
function(event) {
values = event.detail.value;
@this.set('{{ $attributes['wire:model'] }}', values);
},
false,
);
let selected = parseInt(@this.get{!! $attributes['selected'] !!}).toString();
choices.setChoiceByValue(selected);
}"
>
<select id="{{ $attributes['prettyname'] }}" wire-model="{{ $attributes['wire:model'] }}" wire:change="{{ $attributes['wire:change'] }}" x-ref="{{ $attributes['prettyname'] }}">
<option value="">{{ isset($attributes['placeholder']) ? $attributes['placeholder'] : '-- Select --' }}</option>
@if(count($attributes['options'])>0)
@foreach($attributes['options'] as $key=>$option)
<option value="{{$key}}" >{{$option}}</option>
@endforeach
@endif
</select>
</div>
You can now reference this select like so:
<x-input.select wire:model="modelname" prettyname="modelprettyname" :options="$array" selected="('modelname')"/>
For array select, you can do
selected="('modelname')['level1']['level2']"
Else use the model name with the selected value:
selected="('modelname')"
For collections you can do options like this:
:options="$collection->pluck('name', 'id')->toArray()"
For anything else make an array:
@php
$array=[];
@endphp
@if(count($returnlist)>0)
@foreach($returnlist as $list)
@php
$array[$list['id']]=$list['name'];
//for collections would be:
//$array[$type=>id]=$type->name;
@endphp
@endforeach
@endif
Multiselect I like to keep these separate but you can have them on the same component with some refactoring.
php artisan make:component input/selectmultiple
Add the following code to the new component:
<div
x-data
x-init="() => {
var choices = new Choices($refs.{{ $attributes['prettyname'] }}, {
itemSelectText: '',
removeItems: true,
removeItemButton: true,
});
choices.passedElement.element.addEventListener(
'change',
function(event) {
values = getSelectValues($refs.{{ $attributes['prettyname'] }});
@this.set('{{ $attributes['wire:model'] }}', values);
},
false,
);
items = {!! $attributes['selected'] !!};
if(Array.isArray(items)){
items.forEach(function(select) {
choices.setChoiceByValue((select).toString());
});
}
}
function getSelectValues(select) {
var result = [];
var options = select && select.options;
var opt;
for (var i=0, iLen=options.length; i<iLen; i++) {
opt = options[i];
if (opt.selected) {
result.push(opt.value || opt.text);
}
}
return result;
}
">
<select id="{{ $attributes['prettyname'] }}" wire-model="{{ $attributes['wire:model'] }}" wire:change="{{ $attributes['wire:change'] }}" x-ref="{{ $attributes['prettyname'] }}" multiple="multiple">
@if(count($attributes['options'])>0)
@foreach($attributes['options'] as $key=>$option)
<option value="{{$key}}" >{{$option}}</option>
@endforeach
@endif
</select>
</div>
You can now reference this multiselect like so:
<x-input.selectmultiple wire:model="modelname" prettyname="modelprettyname" :options="$array" :selected="$selected" />
I tend to add this before each:
@php
$selected = (json_encode($selectvalues));
@endphp
@php
$array=[];
@endphp
@if(isset($returnlist) && count($returnlist)>0)
@foreach($returnlist as $list)
@php
$array[$list['id']]=$list['name'];
//for collections would be:
//$array[$type=>id]=$type->name;
@endphp
@endforeach
@endif
Note: these are not perfect I wrote them quickly but do the Job
I am on discord from time to time if need help as well cheers
Andy