'v-model on Component returning type string instead of type null
I'm trying to create a Vue 3 component that can handle a v-model binding. The component contains a simple <select>.
The 1st <option> contains a null value with the inner text 'Default placeholder'. The others <option> contain actual values.
If I try to select the option with the null value, rather than returning null it returns the inner text 'Default placeholder'.
I need it to return null.
I can get the null value (see the changeValue() method) but it feels hacky using event.target.selectedOptions[0]._value.
If I try to build the same functionality without using a custom component using v-model then it works as expected.
Child Component
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
emits: ['update:modelValue'],
methods: {
changeValue(event) {
// Output the event for testing purposes
console.dir(event);
console.log(event.target.value);
console.dir(event.target.selectedOptions[0]);
console.log(event.target.selectedOptions[0].text);
// This is the correct value but im unsure if I can use it.
console.log(event.target.selectedOptions[0]._value);
console.log(typeof event.target.value);
// Emit the handler
this.$emit('update:modelValue', event.target.value);
}
},
name: 'HtmlSelect',
props: ['modelValue'],
})
</script>
<template>
<select :value='modelValue' @input="changeValue">
<option :value="null">Should be null. Get inner text.</option>
<option :value="1">Number: 1</option>
<option value="1">String: 1</option>
<option :value="'Some Text'">String: Some Text</option>
</select>
</template>
The parent instance is not doing anything special.
Parent Component
<html-select v-model="someVal"></html-select>
** Edit ** I've simplified the example component to better illustrate the error. Added a link to a working example.
Solution 1:[1]
It's related to how <option> gives you a value. null is an absence of a value. If the value of the option is nullish, then text between opening and closing tags returned. Try use "0" instead of null and check for "0", not null, and then replace "0" with null if you really need null
Solution 2:[2]
If you need to retain the values original type then you must use a computed getter / setter within the component along with a v-model binding.
Working Code
export default defineComponent({
computed: {
value: {
get() {
return this.modelValue;
},
set(value: any) {
this.$emit('update:modelValue', value);
}
}
},
data() {
return {
selectOptions: {
'Null Option': null,
'Numeric Option': 1,
'String Option': 'String'
}
}
},
emits: ['update:modelValue'],
name: 'HtmlSelect',
props: {
modelValue: {
type: String,
default: null
}
},
template: '<select v-model="value">' +
'<option v-for="(option, i) in selectOptions" :value="option">{{ i }}</option>' +
'</select>'
})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Andrew Berridge |
