In the same fashion as custom labels (http://sagalbot.github.io/vue-select/#ex-labels) how do I set my custom value for when my options is an array of objects?
I also want this feature when I read the docs for the first time.
The value is the Object itself by default.
If you want to get custom value without modifying vue-select itself, you may try to set the onChange(val) prop.
Now my solution is to get the "custom value" from the "value Object":
computed: {
customValues() {
let custom_val = []
for(let val of this.modelValues) {
custom_val.push(val.property)
}
return custom_val
}
}
The following behavior seems to defeat the expected functionality of v-model.
<v-select v-model="countryCode" :options="countriesWithLabels"></v-select>
```js
import vueSelect from 'vue-select'
export default {
data() {
countryCode: 'US',
countriesWithLabels: [
{
label: 'United States',
value: 'US'
},
{
label: 'France',
value: 'FR'
},
{
label: 'United Kingdom',
value: 'UK'
}
]
},
components: {
'v-select': vueSelect
}
}
## Problems
Loading v-select while `countryCode` is set to a string such as "US" produces the following problems:
1. v-select fails to match "US" to the corresponding option that labels it as "United States", and renders the option as "US".
2. Upon choosing a different option from the dropdown list, **v-select updates the value of the v-model** (`countryCode`) **to _the option object itself_, rather than `option.value`**.
```js
// Expected result when selecting "United Kingdom" option
data() {
...
countryCode: 'UK',
...
}
// Actual result
data() {
...
countryCode: {
label: 'United Kingdom',
value: 'UK'
},
...
}
v-select should update its v-model with the value property of the currently selected option, not with the whole option object itself.
Same here, any solution?
The root of this behavior seems to be in the getOptionLabel function. I've made a rough fix, but cannot be sure that it'll behave in every possible scenario. Works for me though :-)
getOptionLabel: {
type: Function,
default(option) {
if (typeof option === 'object') {
if (this.label && option[this.label]) {
return option[this.label]
}
} else if (typeof option === 'string') {
let label = null
this.options.forEach(opt => {
if (typeof opt === 'object' && opt[this.value] === option[this.label]) {
label = opt[this.label]
} else if (typeof opt === 'object' && opt[this.value] === option) {
label = opt[this.label]
}
});
if (label != null) return label
}
return option;
}
},
Code can be found in my fork of the library:
https://github.com/vitamink/vue-select/blob/master/src/components/Select.vue~~
@vitamink if it fixes the problem, you should consider making a pull request with your changes on this repository. That would be awesome 馃帀
There were a few other subtleties to fix, but I'm happy with the changes and have submitted a pull request.
If I introduced any bugs with this change then I'm happy to fix them. The use case described by @htunnicliff is exactly my use case, so I'm kinda invested now :-)
Have a good day, folks.
@htunnicliff If you want to try my fix you can get it here:
https://raw.githubusercontent.com/vitamink/vue-select/bootstrap4/dist/vue-select.js
It should work with your use-case, and I'd appreciate any feedback.
@htunnicliff I have the same problem
I totally agree with this issue and that it should be changed. The component should (at least be able to) bind some particular property (e.g. 'value') of the option object and not the whole object. I don't see any real life scenario in which the actual value you want to bind is the whole option object.
I was struggling with this problem myself, so I wrote a wrapper component which emulates the requested functionality. You are free to use it, until the functionality is added to vue-select itself. The code uses 2 functions from Lodash (omit, isEqual), but if you don't use Lodash, they shouldn't be that hard to re-write using core JS.
<!-- Wrapper for multiselect component -->
<script>
import vueSelect from 'vue-select';
import isEqual from 'lodash-es/isEqual';
import omit from 'lodash-es/omit';
export default {
components: {
vueSelect,
},
props: {
// Used by v-model
value: {
type: Array,
required: true,
default: () => [],
},
options: {
type: Array,
required: true,
validator: options => {
let requiredProperties = ['value', 'label'];
return options.every(option =>
requiredProperties.every(option.hasOwnProperty, option)
);
},
},
},
computed: {
listeners() {
// Delete input and change handlers so that they don't capture native
// input and change events. They will still fire, but triggered by
// custom input and change events emitted in the localModel setter.
return omit(this.$listeners, ['input', 'change']);
},
// Needed to work around the fact that vue-select component sets the value of
// the select incorrectly - instead of setting it to array of option values
// (option.value property), it sets it to array of option objects
localModel: {
get() {
return this.valueInputTransformed();
},
set(valueNew) {
// Using valueInputTransformed() (instead of this.localModel) to get
// the real input value, as vue-select modifies the array returned by
// getter for localModel, while the getter is cached and will be not
// run until valueInputTransformed changes.
//
// isEqual is a deep comparison (by values, not by references). The
// comparison needs to be made, as the setter is also run after changing
// the input value and if events are emitted every time the setter is
// run, endless loop of events occur.
if (!isEqual(valueNew, this.valueInputTransformed())) {
let valueOutput = valueNew ? valueNew.map(v => v.value) : [];
this.$emit('input', valueOutput);
this.$emit('change', valueOutput);
}
},
},
},
methods: {
// Transforms the input value (array of values) to the format used by
// vue-select (array of objects with 'value' property) using the exact objects
// from options prop.
valueInputTransformed() {
let valueInput = this.value ? this.value : [];
return valueInput.map(optionValue =>
this.options.find(option => option.value === optionValue)
);
},
},
};
</script>
<template>
<vue-select
v-model="localModel"
multiple
:options="options"
v-bind="$attrs"
v-on="listeners"
/>
</template>
Then if you import this component as BaseMultiselect can use it as below. options is array of objects of format { label, value } (e.g. [ { label: 'Orange', value: 'orange' }, { label: 'Apple', value: 'apple' }, { label: 'Banana', value: 'banana' } ]), while value will be array of 'value' properties of selected objects (e.g. [ 'orange', 'banana' ]).
<base-multiselect
v-model="value"
:options="options"
// Some other props/listeners passed to vue-select
/>
In the scenario I'm using it, value (the one bound in <base-multiselect>) actually comes from Vuex store. As you shouldn't (and cannot in strict mode) modify the values in store directly, I'm using a computed value with setter which commits mutation. Code below. Posting it just in case someone is in a similar situation.
computed: {
value: {
get() {
return this.$store.state.storePropertyName;
},
set(value) {
this.$store.commit('mutationName', { value });
}
}
}
v.2.5.0 introduced the index prop and resolves this issue.
v.2.5.0introduced theindexprop and resolves this issue.
Yeah, it works, thanks.
But please update your Documentation.

https://vue-select.org/api/props.html
@necheporenko index was removed in v3 in favor of reduce. I haven't released versioned docs yet.
Most helpful comment
The following behavior seems to defeat the expected functionality of
v-model.Component
```js
import vueSelect from 'vue-select'
export default {
data() {
countryCode: 'US',
countriesWithLabels: [
{
label: 'United States',
value: 'US'
},
{
label: 'France',
value: 'FR'
},
{
label: 'United Kingdom',
value: 'UK'
}
]
},
components: {
'v-select': vueSelect
}
}
v-select should update its v-model with the
valueproperty of the currently selected option, not with the whole option object itself.