I want to pre-select a particular value in a select drop-down generated by vue-multiselect
.
I can get this to work fine if I have a simple array of strings like the following:
['Test 1', 'Test 2', 'Test 3']
However, when I use an array of objects, I can't get this to work. For example, if I have the following:
<v-multiselect :options="[{id: 1, name: 'Test 1'}, {id: 2, name: 'Test 2'}, {id: 3, name: 'Test 3'}]"
label="name"
track-by="id"
v-model="test">
</v-multiselect>
No matter what I set the test
data property that v-model is connected to, it won't preselect the value. I've tried 1
, 2
, 3
, '1'
, '2'
and '3'
for test
when track-by
is id
and 'Test 1'
, etc. when track-by
is name
but nothing seems to work.
What am I doing wrong here? I looked at the docs at https://vue-multiselect.js.org/#sub-single-select-object, but they don't seem to provide an example when you want to preset a value for an array of objects for the options. Googling has also not returned what I'm looking for.
On a related topic, once I get this working, what would I have to change to select multiple values for when I set the component to multiple
? Thank you.
track-by
usageThe docs indicate that track-by
is "Used to compare objects. Only use if options are objects."
That is, it specifies the object key to use when comparing the object values in options
. The docs should actually state that track-by
is required when the options are objects because <vue-multiselect>
uses track-by
to determine which options in the dropdown are selected and to properly remove a selected option from a multiselect.
Without track-by
, you'd see two buggy behaviors for object-options: (1) the user would be able to re-select already selected options, and (2) attempting to remove selected options would instead cause all options to be re-inserted.
<vue-multiselect>
doesn't support automatically translating a value array, but you could easily do that from the parent component.
Create a local data property to specify track-by
and initial multiselect values (e.g., named trackBy
and initialValues
, respectively):
export default {
data() {
return {
//...
trackBy: 'id',
initialValues: [2, 5],
}
}
}
Bind <vue-multiselect>.track-by
to this.trackBy
and <vue-multiselect>.v-model
to this.value
:
<vue-multiselect :track-by="trackBy" v-model="value">
Create a watcher on this.initialValues
that maps those values into an object array based on this.trackBy
, setting this.value
to the result:
export default {
watch: {
initialValues: {
immediate: true,
handler(values) {
this.value = this.options.filter(x => values.includes(x[this.trackBy]));
}
}
}
}
Vue.component('v-multiselect', window.VueMultiselect.default);
new Vue({
el: '#app',
data () {
return {
trackBy: 'id',
initialValues: [5,2],
value: null,
options: [
{ id: 1, name: 'Vue.js', language: 'JavaScript' },
{ id: 2, name: 'Rails', language: 'Ruby' },
{ id: 3, name: 'Sinatra', language: 'Ruby' },
{ id: 4, name: 'Laravel', language: 'PHP' },
{ id: 5, name: 'Phoenix', language: 'Elixir' }
]
}
},
watch: {
initialValues: {
immediate: true,
handler(values) {
this.value = this.options.filter(x => values.includes(x[this.trackBy]));
}
}
}
})
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]"></script>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/vue-multiselect.min.css">
<div id="app">
<v-multiselect :track-by="trackBy"
:options="options"
v-model="value"
label="name"
multiple>
</v-multiselect>
<pre>{{ value }}</pre>
</div>