I have created a form component in Vue 3 where I am trying to bind a reference object to input elements and from my understanding of two-way binding and how Vue behaved for my past works, I expected any changes to affect my reference object immediately without requiring any manipulation like I would have had to for a React component by triggering the "onChange" react event.
However, when I click on the "Save" button to trigger a function that outputs the reference object, it only seems to keep my value loaded initially but not any changes I make from within the input. Can anybody explain why?
Here's the code for my component. It loads inside a pop-up window.
<script setup lang="ts">
import type { Activity } from '@/models/activity';
import { ref } from "vue";
import Button from '../../common/Button.vue';
defineEmits([
"close-form"
]);
const props = defineProps<{
title?: String,
activity?: Activity,
editMode: Boolean
}>();
const initialState = props.activity ?? {
id: '',
title: '',
category: '',
description: '',
date: '',
city: '',
venue: ''
}
const currActivity = ref<Activity>(initialState);
const handleSubmit = () => {
console.log(currActivity.value);
}
// const handleInputChange = (event: Event) => {
// const {name, value} = event.target as HTMLInputElement;
// console.log(name, value);
// // currActivity.value[name] = value;
// }
</script>
<template>
<form
class="grid grid-cols-5 gap-4 mb-8"
@submit="handleSubmit"
autocomplete="off"
>
<h2
v-if="title"
class="col-span-5 mb-4 text-white text-3xl font-semibold"
>
{{ title }}
</h2>
<input type="text" placeholder='Title' class='col-span-3 mb-4 px-2 py-1 rounded' :value="currActivity.title" name="title" />
<input type="text" placeholder='Category' class='mb-4 px-2 py-1 rounded' :value="currActivity.category" name="category" />
<textarea placeholder='Description' class='col-span-5 mb-4 px-2 py-1 rounded' :value="currActivity.description" name="description" />
<input type="text" placeholder='Date' class='px-2 py-1 rounded' :value="currActivity.date" name="date" />
<input type="text" placeholder='City' class='px-2 py-1 rounded' :value="currActivity.city" name="city" />
<input type="text" placeholder='Venue' class='px-2 py-1 rounded' :value="currActivity.venue" name="venue" />
<div
v-if="editMode && activity"
class="flex justify-end col-span-2"
>
<Button
text="Save"
icon="fa-floppy-disk"
type="send"
@click="handleSubmit"
/>
<Button
text="Close"
icon="fa-xmark"
type="cancel"
@click="$emit('close-form')"
/>
</div>
<div
v-else
class='flex justify-end col-span-2'
>
<Button
text="Post"
icon="fa-paper-plane"
type="send"
@click="handleSubmit"
/>
</div>
</form>
</template>
You may notice a commented function in my script. I tried to replicate the React approach and handle the changes on the change event triggered using "@change" on the input elements. I removed these later as that didn't seem to work. I kept the commented function however in case anyone finds it useful to locate the issue.
You need to make two-way binding using v-model
instead of :value
:
<input type="text" placeholder='Title'
class='col-span-3 mb-4 px-2 py-1 rounded' v-model="currActivity.title" name="title" />