I am trying to set the checked value of a Radio Button list in Vue.JS 2. I've reviewed existing articles here and tried them and also several different manual approaches and I just cannot get this to work at all.
I am NOT using v-model here as I'm working on a custom radio button list control which is consumed by a forms builder. This is further complicated by the fact that I am building, on top, a nested radio button list to handle nullable booleans. Putting that complexity aside, my radio component looks like this....
<template>
<div class="form__radio-list">
<span class="form__radio-list__intro">{{ introText }}</span>
<ul class="form__radio-list__options">
<li v-for="item in options"
:key="item.key ? item.key : item"
class="form__radio-list__options__item">
<input type="radio"
:id="item.key ? item.key.toKebabCase() : item.toKebabCase()"
:name="def"
:value="item.value != undefined ? item.value : item"
:disabled="disabled"
:checked="isChecked(item)"
@input="onInput"
@change="$emit('change', $event.target.checked)">
<label :for="item.key ? item.key : item">{{ item.text ? item.text : item }}</label>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
def: {
type: String,
required: true
},
introText: {
type: String,
default: ''
},
options: {
type: Array,
required: true
},
initialValue: {
type: [String, Number, Boolean],
default: null
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
value: this.initialValue
}
},
methods: {
_parseValue() {
return this.value ? parseInt(this.value) : null
},
isChecked(item) {
const checked = item.value === this.value || item === this.value || item.value == this._parseValue()
this.$logger.logObject({ item, parentValue: this.value, checked }, 'Checking value for an item')
return checked
},
onInput($event) {
this.value = $event.target.checked
this.$emit('input', $event.target.checked)
}
}
}
</script>
From the logging I can see that the value of 'checked' SHOULD be set correctly (but it isn't).
I also tried splitting the input tag into a 'v-if' statement so I'd have one with a checked parameter set and one without (although this felt horrible) and that worked from an HTML point of view (checked="checked" appeared where I would expect it to) but, on the browser neither of the 2 options were checked.
I am consuming the component through a boolean component renederer that looks like this...
<template>
<hh-radio class="form__radio-list--yes-no"
:def="def"
:intro-text="introText"
:options="options"
:initial-value="initialValue"
:disabled="disabled"
@change="$emit('change', $event)"
@input="$emit('input', $event)" />
</template>
<script>
export default {
props: {
def: {
type: String,
required: true
},
introText: {
type: String,
default: ''
},
initialValue: {
type: [String, Boolean],
default: null
},
disabled: {
type: Boolean,
default: false
}
},
computed: {
options() {
return [{
key: 'yes',
text: 'Yes',
value: true
}, {
key: 'no',
text: 'No',
value: false
}]
}
}
}
</script>
This is then consumed ultimately on a form like this...
<hh-yes-no class="editable-segment-field__bool"
:def="pvc-enabled"
:initial-value="pvc.value"
@input="onInput" />
The value pass throughs seem to work fine - The key issue that I have is that it will NOT specify the currently selected item from any existing data.
I have tried suggestions here - Vue.JS radio input without v-model and here - Vue.JS checkbox without v-model without much success.
Using the example given me below I've tried to strip this back as far as I can, adding in pieces of the dynamic elements from my components as I go to identify the problem root.
I now have a simpler component which looks like this...
<template>
<div :class="`form__radio-list ${(this.def ? `form__radio-list--${this.def} js-${this.def}` : '' )}`">
<span class="form__radio-list__intro">{{ introText }}</span>
<ul class="form__radio-list__options">
<li class="form__radio-list__options__item">
<input id="awesome"
type="radio"
name="isawesome"
:checked="radio === 'Awesome'"
value="Awesome"
@change="radio = $event.target.value">
<label for="awesome">Awesome</label>
</li>
<li class="form__radio-list__options__item">
<input id="super"
type="radio"
name="isawesome"
:checked="radio === 'Super Awesome'"
value="Super Awesome"
@change="radio = $event.target.value">
<label for="super">Super</label>
</li>
</ul>
<span>Selected: {{ value }} | {{ radio }}</span>
</div>
</template>
<script>
export default {
props: {
def: {
type: String,
required: true
},
introText: {
type: String,
default: ''
},
initialValue: {
type: [String, Boolean],
default: null
},
disabled: {
type: Boolean,
default: false
}
},
// delete this
data() {
return {
value: this.initialValue,
radio: 'Awesome'
}
},
computed: {
options() {
return [{
key: 'yes',
text: 'Yes',
value: true
}, {
key: 'no',
text: 'No',
value: false
}]
}
}
}
</script>
I managed to get this to fail as soon as I added name="isawesome"
to the radio button items. It seems that when you introduce 'name' something goes awry. Surely I need 'name' to prevent multiple radio button lists interacting with each other or is this something that Vue handles which I've been unaware of.