Vuejs - Weird display when programmatically creating a v-radio-group using Vue.extend

Viewed 15

getting inspired by this webpage, I tried to create and add Vue components to one of my templates at runtime. I actually managed pretty well with a v-switch-based template, but I also needed to do the same with a v-radio-group-based template having basically the same structure and that's things are gettings pretty weird.

To sum up, each home made component should get an ID, a label, a default value plus any other more specific properties (such as options for a v-radio-group, for example). Here is what I've done for checkboxes:

child .ts file

export default class CheckboxComponent extends Vue {
    @Prop({required: false, type: Boolean, default: null})
    public defaultValue: boolean;

    @Prop({required: true, type: Number, default: 0})
    public id: number;

    @Prop({required: true, type: String, default: ""})
    public label: string;

    public yes: boolean = false;
    public no: boolean = false;

...

    public onYesChanged(): void {
        if (this.yes) {
            this.no = !this.yes;

            this.$emit("change", this.id, this.yes);
        } else if (!this.no) {
            this.$emit("change", this.id, undefined);
        }
    }

    public onNoChanged(): void {
        if (this.no) {
            this.yes = !this.no;

            this.$emit("change", this.id, this.yes);
        } else if (!this.no) {
            this.$emit("change", this.id, undefined);
        }
    }
}
child .vue file

<template>
    <v-row dense>
        <v-col cols="8">
            {{ label }}
        </v-col>

        <v-col cols="2">
            <v-switch
                v-model="yes"
                label="Yes"
                color="success"
                @change="onYesChanged"
            />
        </v-col>

        <v-col cols="2">
            <v-switch
                v-model="no"
                label="No"
                color="red"
                @change="onNoChanged"
            />
        </v-col>
    </v-row>
</template>

<script lang="ts" src="./CheckboxComponent.ts"></script>

(Don't ask me why there have to be two v-switch, that's how my project manager designed it)

And then in the parent .ts file:

    let CheckboxClass = Vue.extend(CheckboxComponent);
    let checkbox = new CheckboxClass({
        propsData: { id: 1, value: null, label: "Some checkbox" }
    });

    checkbox.$mount();
    (this.$refs.container as HTMLElement).appendChild(checkbox.$el);
    checkbox.$on("change", this.onCheckboxValueChanged);

And that works perfectly fine:

enter image description here

But if I try to do the same with v-radio-group instead, it goes like this:

child .ts file

export default class RadioButtonComponent extends Vue {
    @Prop({required: false, type: String, default: null})
    public defaultValue: string;

    @Prop({required: true, type: Number, default: 0})
    public id: number;

    @Prop({required: true, type: String, default: ""})
    public label: string;

    @Prop({required: true, type: Array, default: () => []})
    public options: string[];

    public value: string = "";

    public mounted(): void {
        this.value = this.defaultValue;
    }

    public onValueChanged(): void {
        this.$emit("change", this.id, this.value)
    }
}
child .vue

<template>
    <v-row dense>
        <v-col cols="6">
            {{ label }}
        </v-col>

        <v-col cols="6">
            <v-radio-group
                v-model="value"
                mandatory
                row
                @change="onValueChanged"
            >
                <v-radio
                    v-for="(option, index) in options"
                    :key="index"
                    :label="option"
                    :value="option"
                />
            </v-radio-group>
        </v-col>
    </v-row>
</template>

<script lang="ts" src="./RadioButtonComponent.ts"></script>

and then in the parent .ts file:

    let RadioButtonClass = Vue.extend(RadioButtonComponent);
    let radioButton = new RadioButtonClass({
        propsData: { id: 2, defaultValue: "One", label: "Some radio button", options: ["One", "Two", "Three", "Four"] }
        });

    radioButton.$mount();
    (this.$refs.container as HTMLElement).appendChild(radioButton.$el);
    radioButton.$on("change", this.onRadioButtonValueChanged);

but it's rendered this way:

enter image description here

Let me explain what I found out, comparing that result to a "regular" added v-radio-group. It seems that all that's wrong comes from the v-input-selection styling:

<i aria-hidden="true" class="v-icon notranslate material-icons theme--light accent--text"\>$radioOn</i\>

As you can see $radioOn stands right in the slot, where it should be empty, plus the class that doesn't seem right as it should either be mdi mdi-radiobox-blank or mdi mdi-radiobox-marked whether the option is selected or not.

If I manually edit the style to the correct one, I'll then get

enter image description here

So, my question is:

  • is it a bug in Vue.extend that alters standard v-radio-group behaviour (I printed out in console and the created object radioButton already has the wrong values)

  • or is it designed to be this way, in order to let the developers customize their component, in which case I'm surely missing something

0 Answers
Related