Using v-model on custom component with select

Say I have the following component:

<template>
    <select v-model="value" @input="$emit('input', $event.target.value)">
        <option :value="null">– Select a ... –</option>
        <option v-for="option in options" :value="option.slug">{{ option.name }}</option>
    </select>
</template>

<script>
export default {
    props: {
        value: String,
    },

    data () {
        return {
            options: [
                { slug: 'test1', name: 'Test 1' },
                // ...
            ],
        };
    },
}
</script>

And used as:

<custom-select v-model="value" required></custom-select>

Of course this works, but I get the warning about mutating a property.

How do I get around this? What am I missing?

2 Likes

i think you want to v-bind in stead of vmodel, since v-model does the v-bind and @input.

So like this:

<template>
    <select :value="value" @input="$emit('input', $event.target.value)">
        <option :value="null">– Select a ... –</option>
        <option v-for="option in options" :value="option.slug">{{ option.name }}</option>
    </select>
</template>

<script>
export default {
    props: {
        value: String,
    },

    data () {
        return {
            options: [
                { slug: 'test1', name: 'Test 1' },
                // ...
            ],
        };
    },
}
</script>
3 Likes

I am struggling with making this select component work properly so I will really appreciate your help!!

For me this select component is not updating the data property in the parent component.

I put the code provided by @fimion in a CustomSelect.vue file and then reference it from another .vue file like this:

<template>
    <div>
        <custom-select v-model="value" required></custom-select>
    </div>
    <div>
        value is {{ value }}
    </div>
</template>

<script>
import CustomSelect from '../components/ui/CustomSelect.vue';

export default {
  components: {
    CustomSelect
  },
  data() {
    return {
        value: ''
    }
  }
};
</script>

On the screen I can see only

value is

displayed because the value data property is empty and not modified by the selected value on the select component.

Can you please help me figure out what I am doing wrong because I have been struggling for a long time with this!

Thank you in advance!

Hey @ltsvetkov are you using Vue 2 or Vue 3?

@fimion I am using Vue 3

Ah! okay cool, then the syntax has changed slightly in vue 3. here is the updated answerd for vue 3 specifically:

<template>
    <select :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
        <option :value="null">– Select a ... –</option>
        <option v-for="option in options" :value="option.slug">{{ option.name }}</option>
    </select>
</template>

<script>
export default {
    props: {
        modelValue: String,
    },

    data () {
        return {
            options: [
                { slug: 'test1', name: 'Test 1' },
                // ...
            ],
        };
    },
}
</script>

You can read more about this in the vue 3 docs here: Components Basics | Vue.js

1 Like

@fimion Thank you, this works now correctly!