My goal is to create a reusable form component similar to
<buy-form :price="price" />
(which would set the price as pre-defined and read-only. I aim to have the flexibility to pass any of the three fields' values amount
, price
, and total
Within the form, there are 3 Vuetify v-text-field
s.
BuyForm.vue
<template>
<v-card>
<v-card-text>
<crypto-input :value.sync="form.amount" :disabled="!!amount" label="Amount"/>
<crypto-input :value.sync="form.price" :disabled="!!price" label="Price"/>
<crypto-input :value.sync="form.total" :disabled="!!total" label="Total"/>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn depressed dark :color="style">BUY</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
import styles from '@/styles/_export.scss'
import CryptoInput from './CryptoInput'
export default {
name: 'BuyForm',
components: { CryptoInput },
props: {
label: {
type: String,
default: null,
},
price: {
default: null,
},
amount: {
default: null,
},
total: {
default: null,
}
},
data: () => ({
form: {
amount: null,
price: null,
total: null,
},
styles,
}),
mounted() {
Object.keys(this.form).forEach((e) => {
this.form[e] = this.$props[e]
})
},
// ...
Progress has been made. Changes in the inputs reflect in the data.form
object.
Now, I want to calculate the remaining field (i.e., if I pass the price
, users can input either the amount or the total, and the other one will be calculated automatically).
I've set up watchers for each field, but encountered a problem:
the watchers fire constantly because when users input the amount
, the total
changes automatically, causing the total
watcher to trigger, which then recalculates and so on.
In most cases, this is acceptable, as the value remains the same. However, I've come across some edge cases where it breaks (when clearing one field, for example).
I attempted to resolve all these issues with a convoluted mess of watcher logic
watch: {
'form.amount': function(newVal) {
if (!this.$props.amount) { // not disabled
let { amount, price, total } = this.form
if (this.$props.price) this.form.total = amount * price
if (this.$props.amount) this.form.price = total / amount
}
},
'form.total': function(newVal) {
if (!this.$props.total) { // not disabled
let { amount, price, total } = this.form
if (this.$props.price) this.form.amount = total / price
if (this.$props.amount) this.form.price = total / amount
}
This is just a basic concept and far from being "functional" or even "good".
Looking ahead, dealing with scenarios where none of the fields are disabled gives me headaches because all three fields will depend on each other, triggering their respective watchers upon any changes, and I need to anticipate all of that....
It feels fundamentally flawed. So, my question is: Is there a preferred method to tackle this? Surely, there must be a better way? Am I overlooking something obvious? Maybe there's even a library that could assist in this task? I haven't found one, and I don't want to spend countless hours on this cumbersome process only to end up with a fragile and bloated result.
Thank you for any guidance :)