I've created a custom radio button component in Vue. The component is set up to take these props: label (string), value (string), checked (boolean), and a vModelValue which serves as the v-model value that will be used on the component. I set the internal reference to the v-model value to be prop: vModelValue and event: 'change'.
I have a computed value called local_vModelValue which gets the vModelValue prop sent down in the v-model on the component and sets it to the v-model internally.
This works correctly as is, except for one problem. Accessibility isn't working correctly. When I use voice over controls, and I have two distinct radio groups made up of three buttons each, it will identify the selected button as 1 of 6 even though it should be 1 of 3. It sees all 6 buttons on the page and acts as if there is one group.
To fix this, I want to put a name attribute in my component in the underlying logic, and I set up a computed property to check if there is a vModelValue. If there is, it sets the name to that vModelValue (or it SHOULD do so). I don't want to have to send a name down as a prop at this point. I want it to just use the vModelValue as the name. (Later I will check if there is a name attribute prop on the component and then it will use that as the name but for now I'm just trying to get it work with the vModelValue as the name.)
The problem is it just won't set the name to that vModelValue coming in.
Here is the component:
CustomRadioButtons.vue
<template>
<div>
<label
tabindex="0"
>
<input
type="radio"
:checked="checked"
v-model="local_vModelValue"
:value="value"
:name="getNameValue"
@change="onChange"
>
<span>
{{ label }}
</span>
</label>
</div>
</template>
<script>
export default {
name: 'CustomRadioButtons',
model: {
prop: 'vModelValue',
event: 'change'
},
methods: {
onChange(event) {
this.$emit('change', event.target.value, this.label, this.name, this.vModelValue)
},
},
props: {
vModelValue: {
type: String,
default: ''
},
label: String,
value: String,
name: {
type: String,
default: ''
},
checked: {
type: Boolean,
default: false
}
},
computed: {
local_vModelValue: {
get(){
return this.vModelValue;
},
set(value) {
this.$emit('change', value)
}
},
getNameValue() {
return this.vModelValue.length > 0 ? this.vModelValue : this.name
}
},
watch: {
vModelValue:{
immediate: true,
handler(){
console.log(this.vModelValue, this.checked, this.name)
}
}
},
}
</script>
App.vue
<template>
<div id="app">
<h3>Custom Radio Buttons 1</h3>
<div v-for="(button, i) in buttons" :key="'buttons'+i">
<CustomRadioButtons :label="button.label" :value="button.value" :checked="true" v-model="cat"></CustomRadioButtons>
</div>
<h3>Custom Radio Buttons 2</h3>
<div v-for="(button, i) in otherButtons" :key="'otherbuttons'+i">
<CustomRadioButtons :label="button.label" :value="button.value" :checked="true" v-model="dog"></CustomRadioButtons>
</div>
</div>
</template>
<script>
import CustomRadioButtons from "@/components/CustomRadioButtons"
export default {
name: 'App',
components: {
CustomRadioButtons
},
data(){
return {
cat: 'cat',
dog: 'dog',
buttons: [{label: 'label 1', value: 'value 1', name: 'name1'}, {label: 'label 2', value: 'value 2', name: 'name1'}, {label: 'label 3', value: 'value 3', name: 'name1'}],
otherButtons: [{label: 'test 1', value: 'value 1', name: 'name2'}, {label: 'test 2', value: 'value 2', name: 'name2'}, {label: 'test 3', value: 'value 3', name: 'name2'}],
}
},
props: ['value'],
}
</script>
Using the computed value of getNameValue causes the whole thing to work very strangely and I never see the name get updated to the vModelValue.