I am using the Vue-Select library with Vue3. My objective is to let the user choose tags from an options list and also be able to create new tags if the tags do not exist in the options list.
This works fine in a child component, but I am having trouble passing/emitting the data up to the parent component. I need the data in the parent because I am going to package it up for form processing later.
How can I successfully get the tags from the child component and into the parent component's formData.tags
property?
The code and sandbox link:
components/PostEditorTags.vue
:
<template>
<v-select
:create-option="(tag) => ({ label: tag, value: tag })"
v-model="selected"
:options="options"
multiple
taggable
@input="$emit('input', selected)"
placeholder="add a tag"
></v-select>
<br />
child component data:
<pre>{{ selected }}</pre>
</template>
<script setup>
import { ref } from 'vue';
import vSelect from 'vue-select';
import 'vue-select/dist/vue-select.css';
defineEmits(['input']);
const options = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' },
{ value: 'three', label: 'Three' },
{ value: 'four', label: 'Four' },
{ value: 'five', label: 'Five' },
{ value: 'six', label: 'Six' },
{ value: 'seven', label: 'Seven' },
{ value: 'eight', label: 'Eight' },
{ value: 'nine', label: 'Nine' },
{ value: 'ten', label: 'Ten' },
];
let selected = ref([]);
</script>
components/Parent.vue:
<template>
<h1>Post Tags</h1>
<PostEditorTags @input="setTagsArr" />
<br />
<br />
parent component data:
<pre>{{ formData.tags }}</pre>
</template>
<script setup>
import PostEditorTags from './PostEditorTags.vue';
const formData = {
// title: '',
// content: '',
tags: null,
};
function setTagsArr(x) {
formData.tags = x;
}
</script>
Try with watcher instead of event
components/PostEditorTags.vue:
<template>
<v-select
:create-option="(tag) => ({ label: tag, value: tag })"
v-model="selected"
:options="options"
multiple
taggable
placeholder="add a tag"
></v-select>
<br />
child component data:
<pre>{{ selected }}</pre>
</template>
<script setup>
import { ref, defineEmits, watch } from 'vue';
import vSelect from 'vue-select';
import 'vue-select/dist/vue-select.css';
const options = [{ value: 'one', label: 'One' }, { value: 'two', label: 'Two' }, { value: 'three', label: 'Three' }, { value: 'four', label: 'Four' }, { value: 'five', label: 'Five' }, { value: 'six', label: 'Six' }, { value: 'seven', label: 'Seven' }, { value: 'eight', label: 'Eight' }, { value: 'nine', label: 'Nine' }, { value: 'ten', label: 'Ten' },];
let selected = ref([]);
watch(
() => selected.value,
(newValue, oldValue) => {
act(newValue);
}
);
const emit = defineEmits(['input'])
const act = (val) => emit('input', val);
</script>
Make your data reactive in components/Parent.vue:
<template>
<h1>Post Tags</h1>
<PostEditorTags @input="setTagsArr" />
<br />
<br />
parent component data:
<pre>{{ formData.tags }}</pre>
</template>
<script setup>
import { reactive } from 'vue'
import PostEditorTags from './PostEditorTags.vue';
const formData = reactive({
// title: '',
// content: '',
tags: null,
});
function setTagsArr(x) {
formData.tags = x;
}
</script>