Reputation: 921
I'm new to Vue.js
and I would like to set some data using a two-way data binding via v-model
(on two separated inputs)
Why I need it: I have two inputs (input[type=number]
and a select
containing "days", "months", "years"). And obviously, these two inputs will be concatenated to a data.
Another constraint is that the user is able to add as many "periods" as they want, so the data is a string in an array. Using v-for="(period, index) in periods"
, it's easy to target a given index in the data array, but it's becoming complicated if I have to use a computed
with a get()
exploding the value, and the set()
concatenating them... But if there is no easier magical way, I'll have to stick to it...
Example HTML:
<agreement inline-template>
<div v-for="(period, index) in ftc_trial_periods">
<input type="number" min="1" v-model="??" required>
<select v-model="??" required>
<option>days</option>
<option>months</option>
<option>years</option>
</select>
</div>
</agreement>
Example Component:
Vue.component('agreement', {
data() {
return {
ftc_trial_periods: []
}
}
});
When a number is changed or when an option is selected, I'd like the value to be concatenated/set/appended in ftc_trial_periods
. For instance, ftc_trial_periods
could be: ['1 day', '3 months']
.
Upvotes: 0
Views: 590
Reputation: 5075
<select>
based on <input>
with validationA solution to your problem would be to use a computed value to create periods
and iterate over this value to create multiple selects with v-for='index in period
, from here we need to bind the value of each select dynamically in an array selectedArray: ['']
. To do this I use the computed property periods
to check for the change in number of periods in the string against the length of selectedArray
. If there are more periods, I .push
another string onto selectedArray
, if there are less, I .pop
the last one off. To bind each select element I use v-bind='selectedArray[index]
. Lastly, we validate the string and check that every select is filled out, if so put all the data together in an array of strings.
Here is the code (below and in JSFiddle):
Vue.js Code:
Vue.component('agreement', {
template: `
<div>
<input
type="text"
v-model="numbers"
/>
<select
v-for='index in periods'
v-model='selectedArray[index - 1]'
required
>
<option>days</option>
<option>months</option>
<option>years</option>
</select>
<p>
{{ output }}
</p>
</div>
`,
data: () => ({
numbers: '',
selectedArray: ['']
}),
computed: {
inputsAreValid: function() {
return this.numbers.match(/^\d+((\.\d+)?)+$/g) && this.selectedArray.every(selection => selection !== '')
},
output: function() {
if (!this.inputsAreValid)
return []
return this.numbers.split('.').map((number, index) => `${number} ${this.selectedArray[index]}`)
},
periods: function() {
const numberOfPeriods = this.numbers.split('.').length
if (numberOfPeriods > this.selectedArray.length)
this.selectedArray.push('')
else if (numberOfPeriods < this.selectedArray.length)
this.selectedArray.pop()
return numberOfPeriods
}
}
})
new Vue({
el: "#app"
})
HTML Template Code:
<div id="app">
<agreement></agreement>
</div>
Upvotes: 0
Reputation: 20855
In this scenario, I would store form values in data and make ftc_trial_periods
a computed value of these data. So no exploding/concatenating is required.
https://jsfiddle.net/jacobgoh101/kgodqmbx/6/
<div id="app">
<button @click="addPeriod">add period</button><br><br>
<div v-for="(form) in formInputs">
<input type="number" min="1" v-model="form.value" required>
<select v-model="form.type" required>
<option>days</option>
<option>months</option>
<option>years</option>
</select>
</div>
ftc_trial_periods: {{ftc_trial_periods}}
</div>
new Vue({
el: "#app",
data: {
formInputs: [
{
value: null,
type: null
}
]
},
computed: {
ftc_trial_periods: function() {
return this.formInputs.map(obj => {
return `${obj.value} ${obj.type}`;
});
}
},
methods: {
addPeriod: function() {
this.formInputs.push({
value: null,
type: null
});
}
}
})
Upvotes: 1