Select and Select Multi

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

1 Like

@andylord565 this is actually a very good post.

I have currently setup using Select2 in my project, unfortunately when researching which Select js library I should use, I did not come across Choices.js

Well, seeing this, and their demo page, next time I definitely will go which Choices next time.

Thanks :+1:

@basepack
Your welcome let me know if you need any help :+1:

Ill post the JS versions for this as well for anyone not using Alpinejs when I get chance