I am using Vue 2 and Vuetify (not Vue 3) to create a form builder website. I was going perfectly well until I found out that something is wrong. So here's the case. I rendered text fields (inputs) from a reactive array using the following code.
<template>
// ... some other unrelated code
<template v-if="answer.type !== 1">
<v-col
v-for="(_, i) in answer.options"
:key="`#question-${answer.id}-${i}`"
cols="12"
>
<div class="flex flex-row justify-between items-center">
<TextField
v-model="answer.options[i]"
class="ml-4"
label="Option"
underlined
hideLabel
/>
<v-btn @click="deleteOption(i)" icon>
<v-icon>mdi-close</v-icon>
</v-btn>
</div>
</v-col>
<v-col>
<TextButton @click="addOption()" text="+ ADD OPTION" />
</v-col>
</template>
// ... some other unrelated code
</template>
<script>
import { reactive, ref, watch } from '@vue/composition-api'
import useInquiry from '@/composables/useInquiry'
import TextButton from '@/components/clickables/TextButton.vue'
import TextField from '@/components/inputs/TextField.vue'
export default {
components: { TextField, TextButton },
setup() {
const { answer, addOption, deleteOption } = useInquiry()
return { answer, addOption, deleteOption }
}
}
</script>
Here's my useInquiry composable logic
import { reactive, watch, se } from '@vue/composition-api'
import ID from '@/helpers/id'
export default () => {
const answer = reactive({
id: ID(), // this literally just generates an ID
type: 2,
options: ['', '']
})
const addOption = () => {
answer.options.push('')
}
const deleteOption = at => {
const temp = answer.options.filter((_, i) => i !== at)
answer.options = []
answer.options = temp
};
return { answer, addOption, deleteOption }
}
And finally, here's my TextField.vue
<template>
<v-text-field
v-model="inputValue"
:label="label"
:single-line="hideLabel"
:type="password ? 'password' : 'text'"
:outlined="!underlined"
:dense="!large"
hide-details="auto"
/>
</template>
<script>
import { ref, watch } from '@vue/composition-api'
export default {
model: {
props: 'value',
event: 'change'
},
props: {
label: String,
value: String,
password: Boolean,
underlined: Boolean,
large: Boolean,
hideLabel: Boolean
},
setup(props, context) {
const inputValue = ref(props.value)
watch(inputValue, (currInput, prevInput) => {
context.emit('change', currInput)
})
return { inputValue }
}
}
</script>
The problem is, everytime the delete button is clicked, the deleted input is always the last one on the array, even though I didn't click on last one. I tried to log my reactive array by watching it using Vue's composition watch method. Apparently, the data is correctly updated. The problem is the v-model looks un-synced and the last input is always the one that gets deleted.