Reputation: 223
I have vue form with dynamic inputs.
1st. user register total shares amount in form
2nd. he start issue this total amount to shareholders partially by adding dynamic inputs as much as he need
3rd he submit the form.
My task is to avoid overissue.
I can' figure out how to avoid issue share to shareholders more than it registred in total/
Ex:
totalSharesAmount = 100
shareholder[0] - shares_amount = 50
shareholder[1] - shares_amount = 20 //70 total
shareholder[2] - shares_amount = 30 //100 total. can't be more than 100
My data:
data() {
return {
totatSharesAmount: 100
shareholders: [{share_amount: '', share_price: ''}]
}
}
My validate method (computed) and here I need help:
sharesToFounders() {
return {
required: true,
max_value: this.totalSharesAmount - this.shareholder['shares_amount'] //need help here
}
}
Upvotes: 3
Views: 1709
Reputation: 43899
You need a computed to keep track of remaining points. You need a function to add elements to your array when there are points remaining. You need to hook up a watcher to call that function. The snippet below does that.
new Vue({
el: '#app',
data() {
return {
totalPoints: 100,
foundersPoints: []
};
},
methods: {
addPoint() {
this.foundersPoints.push({
points_amount: null,
point_price: null
});
}
},
watch: {
remainingPoints: {
handler(v) {
if (v > 0 && this.pointValues.every((v) => v > 0)) {
this.addPoint();
}
if (v <= 0 || isNaN(v)) {
// Remove any zeros, probably just the last entry
this.foundersPoints = this.foundersPoints.filter((o) => o.points_amount > 0);
}
},
immediate: true
}
},
computed: {
pointValues() {
return this.foundersPoints.map((o) => o.points_amount);
},
remainingPoints() {
const used = this.pointValues.reduce((a, b) => a + b, 0);
return this.totalPoints - used;
}
}
});
:invalid {
border: solid red 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="p in foundersPoints">
<input v-model.number="p.points_amount" type="number" min="1" :max="p.points_amount + remainingPoints">
</div>
<div>Remaining shares: {{remainingPoints}}</div>
</div>
Upvotes: 1
Reputation: 1983
One way to solve it: keep track of the current total, and on input, use a validator method to either allow the user's change, or prevent it.
Markup:
<div id="app">
<div class="row"><span>Total:</span><input type="number" v-model="totalPoints"></div>
<div v-for="(item, index) in foundersPoints" class="row">
<input type="number" v-on:input="updateValue(index)" v-model="foundersPoints[index].points_amount"><span v-if="foundersPoints[index].alert" class="alert">{{foundersPoints[index].alert}} <button v-on:click="dismissAlert(index)">OK</button></span>
</div>
</div>
Validator method:
updateValue(idx) {
let value;
if (this.tempSum > this.totalPoints) {
const overage = this.totalPoints - this.tempSum;
value = Number(this.foundersPoints[idx].points_amount) + overage;
} else {
value = Number(this.foundersPoints[idx].points_amount);
}
this.foundersPoints[idx].points_amount = value;
},
Current total (a computed property) used to keep track of the :
computed: {
tempSum() {
const pointsAmounts = this.foundersPoints.map(item => Number(item.points_amount));
return pointsAmounts.reduce((acc, t) => acc + Number(t), 0);
}
},
See it in action in this fiddle: https://jsfiddle.net/ebbishop/vu508Lgc/
This does not handle the case where a user reduces the total points allowed. (User had total = 60 and then set each of the three points values to 20. If the user then changes the total to 40, what happens to the inputs that add up to 60?)
Upvotes: 1