I have an existing form in a Vue 3 project that posts successfully to a Cloud Firestore database.
How do I use change two of the type="text"
input fields into tag inputs, using a Tag Input Component like this? Here's a link to it on CodeSandbox
The standalone tutorial is very clear and works fine. What I'm struggling with is how to incorporate that into an existing Vue 3 form and continue posting everything to the Firestore database.
I stripped-away styles and many other input fields from the "base" code below:
<template>
<form @submit.prevent="handleSubmit" >
<h3>What kind of pet?</h3>
<div class="space-y-0">
<select required name="pet_type" id="pet_type" v-model="pet_type">
<option value="">Please select</option>
<option value="cat">Cat</option>
<option value="dog">Dog</option>
<option value="wolverine">Wolverine</option>
</select>
</div>
<hr>
<div> <!-- Want to change this into the first tag input -->
<h3>Pros</h3>
<div for="petPros">What are 3 positive things about this pet?</div>
<input type="text" placeholder="separate , with , commas" id="petPros" v-model="petPros">
<label for="petPros">separate , with , commas</label>
</div>
<hr>
<div>
<h3>Cons</h3> <!-- Want to change this into a second tag input -->
<div for="petCons">And what are 3 negative things about this pet?</div>
<input type="text" placeholder="separate , with , commas" id="petPros" v-model="petCons">
<label for="petCons">separate , with , commas</label>
</div>
<hr>
<h3>Privacy</h3>
<div>
<div>
<input type="radio" id="Fullpublic" value="Fullpublic" name="reviewPrivacy" required v-model="reviewPrivacy">
<label class="text-base inline-flex ml-4 align-bottom" for="Fullpublic">Public</label>
</div>
<div>
<input type="radio" id="keepFullyPrivate" value="keepFullyPrivate" name="reviewPrivacy" required v-model="reviewPrivacy">
<label class="text-base inline-flex ml-4 align-bottom" for="keepFullyPrivate">Private</label>
</div>
</div>
<hr>
<button v-if="!isPending" >Submit</button>
<button v-else disabled>Saving...</button>
</form>
</template>
<script>
import { ref } from 'vue'
import useStorage from '@/composables/useStorage'
import useCollection from '@/composables/useCollection'
export default {
setup() {
const { filePath, url, uploadImage } = useStorage()
const { error, addDoc } = useCollection('reviews')
const { user } = getUser()
const router = useRouter()
const pet_type = ref('')
const petPros = ref('')
const petCons = ref('')
const reviewPrivacy = ref('')
const file = ref(null)
const fileError = ref(null)
const isPending = ref(false)
const handleSubmit = async () => {
if (file.value) {
isPending.value = true
await uploadImage(file.value)
const res = await addDoc({
pet_type: pet_type.value,
petPros: petPros.value,
petCons: petCons.value,
reviewPrivacy: reviewPrivacy.value,
userId: user.value.uid,
userName: user.value.displayName,
createdAt: timestamp()
})
isPending.value = false
if (!error.value) {
router.push({ name: 'ReviewDetails', params: { id: res.id }})
}
}
}
// allowed file types
const types = ['image/png', 'image/jpeg']
const handleChange = (e) => {
let selected = e.target.files[0]
console.log(selected)
if (selected && types.includes(selected.type)) {
file.value = selected
fileError.value = null
} else {
file.value = null
fileError.value = 'Please select an image file (png, jpg or jpeg)'
}
}
return { pet_type, petPros, petCons, reviewPrivacy, handleSubmit, fileError, handleChange, isPending }
}
}
</script>
<style>
</style>
Thanks for any help!
CodePudding user response:
In the form, replace the two
<input type="text">
s with<TagInput>
. Keep thev-model
the same, asTabInput
implementsv-model
.<!-- BEFORE --> <input type="text" placeholder="separate , with , commas" id="petPros" v-model="petPros"> <input type="text" placeholder="separate , with , commas" id="petPros" v-model="petCons"> <!-- AFTER --> <TagInput id="petPros" v-model="petPros" /> <TagInput id="petCons" v-model="petCons" />
Locally register
TagInput.vue
in the form component:import TagInput from "./TagInput.vue"; export default { components: { TagInput, }, }
Change the initial values of
petPros
andpetCons
ref
s to arrays, as theTabInput
outputs a string array of the input tag values:// BEFORE const petPros = ref('') const petCons = ref('') // AFTER const petPros = ref([]) const petCons = ref([])
TabInput
normally adds a tag upon hitting TAB, but your placeholder suggests that you want to use the comma key , instead. To do that, update the modifier in the@keydown
binding:<!-- BEFORE --> <input v-model="newTag" @keydown.prevent.tab="addTag(newTag)" > <!-- AFTER --> <input v-model="newTag" @keydown.prevent.,="addTag(newTag)" >