[Composition API] Component v-model expecting Array but string given I'm using Vue 3.3.4
I want to make a re-usable select component
<!--Parent.vue-->
<template>
<Child v-model="dataForm.options" multiple>
<option v-for="opt in choices" :value="opt.title" :key="opt.id">{{ opt.title }}</option>
</Child>
</template>
<script>
import { ref } from "vue";
import Child from './Child.vue';
export default {
components: { Child },
setup() {
const dataForm = ref({
options: []
});
return { dataForm }
}
}
</script>
<!--Child.vue-->
<template>
<select v-bind="$attrs" :value="modelValue" @change="$emit('update:modelValue', $event.target.value)">
<slot/>
</select>
</template>
<script>
import { ref } from "vue";
export default {
props: {
modelValue: null,
//...
},
setup(props) {
//...
}
}
</script>
Whenever I choose multiple options it only passes 1 value. What could be the solution for this? I know I could just update the Vue version and use the updated syntax but I want to know what could be the solution for this
Hi @chron
Hi think the problem could be on the emit. Can you try something like this?
Parent Component
<template>
<ChildComponent v-model="dataForm.options"></ChildComponent>
</template>
<script>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
setup() {
const dataForm = ref({
options: []
});
return { dataForm };
}
};
</script>
Child component
<template>
<select @change="updateValue">
<option>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</select>
</template>
<script>
export default {
props: {
modelValue: {
type: Array,
default: () => []
}
},
emits: ['update:modelValue'],
methods: {
updateValue(e) {
this.$emit('update:modelValue', e.target.value);
}
}
};
</script>
@dualklip I'm using the Composition API syntax so the syntax is a bit different. emit is doing its thing, it just passes incorrect data.
Yes, but the essence is the same
Parent component
<template>
<ChildComponent v-model="dataForm.options"></ChildComponent>
</template>
<script>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
setup() {
const dataForm = ref({
options: []
});
return { dataForm };
}
};
</script>
Child component
<template>
<select v-model="selectedValue">
<option>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</select>
</template>
<script>
import { computed, toRef } from 'vue';
export default {
props: {
modelValue: Array
},
setup(props, { emit }) {
const selectedValue = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
});
return {
selectedValue
};
}
};
</script>
Perhaps you are looking something that build the entire array like this
Parent component
<script>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
setup () {
const dataForm = ref({
options: [
{id: 1, label: 'Option 1', selected: false},
{id: 2, label: 'Option 2', selected: false},
{id: 3, label: 'Option 3', selected: false}
]
});
return {dataForm};
}
};
</script>
<template>
<ChildComponent :options="dataForm.options"></ChildComponent>
<div>{{dataForm.options}}</div>
</template>
Child component
<script>
export default {
props: {
options: Array
},
setup(props) {
const onSelectChange = (e) => {
props.options.forEach((option) => {
option.selected = (option.label === e.target.value);
});
};
return { onSelectChange };
}
};
</script>
<template>
<select @change="onSelectChange">
<option v-for="(option, index) in options" :key="index"
:value="option.label" :selected="option.selected">
{{ option.label }}
</option>
</select>
</template>
example
Please sign in or create an account to participate in this conversation.