2

I'm looking for an example on how to code a custom component that displays a number of options as radio buttons (passed as props to the custom component), of which only one radio button is selected at the time and with two-way binding. I also need this using the Composition API.

I have this custom component at the moment:

<template>
    <Label :label="fieldLabel" :required="required" />
    <div v-for="item in items" :key="item.id">
        <input type="radio" :value="item.id" @input="$emit('input:model', $event.target.value)">
        {{ item.label }}
    </div>
</template>

<script>
import { db } from '@/firebase/config'
import { onMounted, ref } from '@vue/runtime-core';

import Label from './Label'

export default {
    name: 'RadioInput',
    components: {
        Label
    },
    props: ['item', 'label', 'model', 'sortby', 'sortorder'],
    emits: ['input:model'],
    setup(props) {
        const fieldLabel = props.label ? props.label : null
        const item = props.item
        const items = ref([])
        const model = props.model;
        const required = props.required !== undefined ? props.required : false;
        const sortBy = props.sortby !== undefined ? props.sortby : 'label';
        const sortOrder = props.sortorder !== undefined ? props.sortorder : 'asc';

        onMounted(() => {
            // Get the collection from firestore
            db.collection(item).orderBy(sortBy, sortOrder).get()
                .then(res => {
                    items.value = res.docs.map(doc => {
                        return { ...doc.data(), id: doc.id }
                    })
                })
        })

        return { fieldLabel, items, model, required }
    }
}
</script>

The items are fetched from a Firebase collection, which works perfectly fine. My issue is that I can check all radio buttons individually and they all stay checked. And the selected value is not bound.

An example of the use of the custom radio group input component I have is like this:

<RadioInput :label="'Commercial Status'" :item="'commercial_status'" :sortby="'sort_order'" :sortorder="'asc'" v-model:model="commercialStatusId" :required="false" />

The result before selection looks like this:

enter image description here

But then I can check all radio buttons, and only one should be checked at the same time:

enter image description here

2 Answers 2

3

Radios not mutually exclusive

This part is not a Vue problem - it is pure HTML ...

Defining a radio group

A radio group is defined by giving each of radio buttons in the group the same name. Once a radio group is established, selecting any radio button in that group automatically deselects any currently-selected radio button in the same group.

Binding

When using v-model with radio, it uses checked property and change event. You are not binding checked and you are handling @input instead of @change

On top of that, your component is using model prop and is emitting input:model event (to parent), but v-model on custom components is expecting modelValue prop and update:modelValue event

Sign up to request clarification or add additional context in comments.

1 Comment

You're absolutely right Michal, thanks. I was too much assuming it had to do with Vue. By assigning a dummy value to the name attribute of the input, I can now only select 1 value. However, the two-way binding isn't working yet, i.e. the default setting isn't happening based on model (even though model has the right value). Any idea what I am missing?
1

Alright, I figured it out. For the default checking I had to add and data-bind the checked attribute. The following code is properly working:

<input type="radio" name="myDummyGroupingName" :checked="item.id==model" class="shadow" :value="item.id" @input="$emit('update:model', $event.target.value)">

plus 'update' instead of 'input' in the script:

emits: ['update:model']

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.