-
-
Save mithicher/9944232624cbad4b1cb5d3d2cac87a97 to your computer and use it in GitHub Desktop.
/* Component Usage | |
// Data for options | |
$users = \App\User::limit(6)->get()->transform(fn($user) => [ | |
'id' => $user->id, | |
'title' => $user->name, | |
'subtitle' => $user->email | |
]); | |
// Usage in view | |
<x-tom-select | |
id="testUser" | |
name="testUser" | |
wire:model="testUser" | |
:options="$users" | |
placeholder="Pick a user" | |
items="{{ $testUser }}" // for multiselect edit eg. 1,2,3 comma separated ids | |
// multiple // enable for multiple select | |
/> | |
*/ | |
@props([ | |
'options' => [], | |
'items' => null | |
]) | |
<div wire:ignore> | |
<select | |
x-data="{ | |
tomSelectInstance: null, | |
options: {{ collect($options) }}, | |
items: [{{ $items }}], | |
renderTemplate(data, escape) { | |
return `<div class='flex items-center'> | |
<span class='mr-3 w-8 h-8 rounded-full bg-gray-100'><img src='https://avatars.dicebear.com/api/initials/${escape(data.title)}.svg' class='w-8 h-8 rounded-full'/></span> | |
<div><span class='block font-medium text-gray-700'>${escape(data.title)}</span> | |
<span class='block text-gray-500'>${escape(data.subtitle)}</span></div> | |
</div>`; | |
}, | |
itemTemplate(data, escape) { | |
return `<div> | |
<span class='block font-medium text-gray-700'>${escape(data.title)}</span> | |
</div>`; | |
} | |
}" | |
x-init="tomSelectInstance = new TomSelect($refs.input, { | |
valueField: 'id', | |
labelField: 'title', | |
searchField: 'title', | |
options: options, | |
items: items, | |
@if (! empty($items) && ! $attributes->has('multiple')) | |
placeholder: undefined, | |
@endif | |
render: { | |
option: renderTemplate, | |
item: itemTemplate | |
} | |
});" | |
x-ref="input" | |
x-cloak | |
{{ $attributes }} | |
placeholder="Pick some links..."></select> | |
</div> | |
@once | |
@push('styles') | |
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/tom-select.css" rel="stylesheet"> | |
<style> | |
.ts-input { | |
padding: 10px 8px; | |
border-radius: 0.5rem; | |
border-color: rgba(209, 213, 219, 1.0); | |
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); | |
} | |
.ts-input.focus { | |
outline: 2px solid transparent; | |
outline-offset: 2px; | |
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), 0 0 0 3px rgba(199, 210, 254, 0.5); | |
border-color: rgba(165, 180, 252, 1.0); | |
} | |
.ts-input.dropdown-active { | |
border-radius: 0.5rem 0.5rem 0 0; | |
} | |
.ts-dropdown { | |
margin: -5px 0 0 0; | |
border-radius: 0 0 0.5rem 0.5rem; | |
padding-bottom: 4px; | |
} | |
.ts-control.single .ts-input:after { | |
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='none' viewBox='0 0 24 24' stroke='%239CA3AF'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M8 9l4-4 4 4m0 6l-4 4-4-4' /%3E%3C/svg%3E"); | |
display: block; | |
position: absolute; | |
top: 10px; | |
right: 8px; | |
width: 24px; | |
height: 24px; | |
border: none; | |
} | |
</style> | |
@endpush | |
@push('scripts') | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/tom-select.complete.min.js"></script> | |
@endpush | |
@endonce |
Thank you so much. I beat my head against the wall trying to make mine work (it always broke when I selected an item).
I think I can reproduce the issue, though I don't understand why it is a problem:
See what happens if you put following just above <x-tom-select ...
in your form blade:
<label for="testUser">WTF</label>
In my case, the addition of the label with id of tom select element snaps it when selecting an item!?!?! Am I seeing ghosts?
One other small change I made since my data id's are strings & @JSON throws double-quotes into the rendered blade, busting the alpine x-data attribute: In tom-select component, I changed
...
items: @json($selectedItems),
...
to
...
items: {{ json_encode($selectedItems) }},
...
It seems happy with that, though I've only tested with single string item.
BTW I just realized that adding a wire:key to that label tag addresses the problem. Very edge-y livewire dom diffing issue, I'd say. I would love if you could reproduce as it is lonely out here on the edge ...
@thumbtech use {{ collect($selectedItems) }}
instead of {{ json_encode($selectedItems) }}
. It works well for nested objects.
Just a lil late, by uhh 2 years. Had a ton of problems, with tom-select but this managed to send me in the correct direction thanks :)
I had written some code to allow for real-time updating of the item list and the selected value so that you can change those in php / server side and have it reflect in the selection.
The fork is here if anyone comes across this and need a more documented and implemented solution https://gist.github.com/CallumCarmicheal/3bcbfb178443c9a11c673be83530ac8d
If your are rending tom-select component conditionally then you need to put the both the css and js in you livewire component.
Hope this helps!