Vue-select tipps with Inertia & Laravel
How to use vue-select with Vue 3 and Laravel. https://vue-select.org/
Basics
The most simplest way to introduce a v-select component is by specifying its options and the model.
<v-select :options="options" v-model="form.address"></v-select>
ID different from value
The variable `options` needs to be an array, if your id is different from your options label. Each option has an id and a label:
public function create()
{
$options = [
['id' => 'de', 'label' => 'Germany'],
['id' => 'uk' , 'label' => 'United Kingdom']
];
return Inertia::render('Welcome', compact('options'));
}
This comes with a new issue, the value of form.address
is not a simple value anymore, but an object containing both an ID and a label. This complicates form submission, as you need to extract the ID from the object. Additionally, it poses challenges in editing scenarios where pre-selecting values requires more than just an ID—you need to provide the whole id/label object. To resolve this, you should use the :reduce
attribute in your v-select
component. By doing so, as shown in the code snippet:
<v-select :options="options" v-model="form.address" :reduce="(option) => option.id"></v-select>
This modification ensures that form.address
will store only the ID, simplifying both the handling of pre-defined values and the process of submitting form data.
public function edit()
{
$options = [
['id' => 'de', 'label' => 'Germany'],
['id' => 'uk' , 'label' => 'United Kingdom']
];
// It is enough to just provide the id of address
$address = 5;
return Inertia::render('Welcome', compact(['options', 'address']));
}
public function store(Request $request)
{
// this will be the id.
$request->input('address');
}
In your VUE component you can now assign the address is to to the form:
const props = defineProps(['address', 'options']);
const form = useForm({ address: props.address });
Multiselect with restrictions
If you want to allow multiple selections, but no more then 3, you can do the following:
<v-select :options="trainerOptions" v-model="form.masterTrainer" :multiple="true" :reduce="(option) => option.id" :selectable="() => form.masterTrainer.length < 3">
</v-select>
Group options
It is currently not possible to group selections: https://github.com/sagalbot/vue-select/issues/342
However, you can do it by a workaround. The workaround is to mix headings and options together like this:
options = [
{ label: "Heading 1 ", heading: true} ,
{ label: "Option A", id: 4, heading: false},
{ label: "Option B", id: 2, heading: false},
{ label: "Heading 2 ", heading: true} ,
{ label: "Option C", id: 8, heading: false},
{ label: "Option D", id: 9, heading: false},
]
You can then fake groups using the template slot and by providing a selectable method:
<v-select :options="options" :reduce="(option) => option.id" v-model="form.qualification" :selectable="selectableOption">
<template #option="{ label, tag, heading }">
<h5 v-if="heading" class="mb-0">{{ label }}</h5>
<span v-else class="ms-3">{{ label }}</span>
</template>
</v-select>
In addition you need to add the following function:
function selectableOption( option ) { return option.heading != true; }