I have a Vue instance with five puted property functions that do the same things for different values. I repeat myself quite a bit and am wondering about a cleaner way to do this without repeating myself so much.
In the HTML template I have five input fields, each input field is limited to 25 characters and I would like to display I display a character counter:
<div class='field is-grouped'>
<p class='control is-expanded'>
<input
class="input"
placeholder="Trophy engraving line 1 (25 character limit)"
v-model='engraving.line1'
v-validate="'required'"
:class="{'input': true, 'is-danger': errors.has('engraving.line1') }"
name='engraving.line1'>
</p>
<p class='control'>
<span>{{ line1count }}</span>
</p>
</div>
I have five fields that look exactly like that except they say engraving.line2
, engraving.line3
, engraving.line4
and engraving.line5
.
Then my ponent javascript I define the engraving object and have the same puted method for each field.
export default {
data(){
return {
engraving: {
line1: '',
line2: '',
line3: '',
line4: '',
line5: '',
}
};
},
puted: {
line1count() {
var chars = this.engraving.line1.length,
limit = 25;
return (limit - chars) + "/" + limit + " characters remaining";
},
line2count(){
var chars = this.engraving.line2.length,
limit = 25;
return (limit - chars) + "/" + limit + " characters remaining";
},
line3count(){
var chars = this.engraving.line3.length,
limit = 25;
return (limit - chars) + "/" + limit + " characters remaining";
},
line4count(){
var chars = this.engraving.line4.length,
limit = 25;
return (limit - chars) + "/" + limit + " characters remaining";
},
line5count(){
var chars = this.engraving.line5.length,
limit = 25;
return (limit - chars) + "/" + limit + " characters remaining";
}
},
How can I resuse this function to accept a data parameter and not repeat myself so much?
I have a Vue instance with five puted property functions that do the same things for different values. I repeat myself quite a bit and am wondering about a cleaner way to do this without repeating myself so much.
In the HTML template I have five input fields, each input field is limited to 25 characters and I would like to display I display a character counter:
<div class='field is-grouped'>
<p class='control is-expanded'>
<input
class="input"
placeholder="Trophy engraving line 1 (25 character limit)"
v-model='engraving.line1'
v-validate="'required'"
:class="{'input': true, 'is-danger': errors.has('engraving.line1') }"
name='engraving.line1'>
</p>
<p class='control'>
<span>{{ line1count }}</span>
</p>
</div>
I have five fields that look exactly like that except they say engraving.line2
, engraving.line3
, engraving.line4
and engraving.line5
.
Then my ponent javascript I define the engraving object and have the same puted method for each field.
export default {
data(){
return {
engraving: {
line1: '',
line2: '',
line3: '',
line4: '',
line5: '',
}
};
},
puted: {
line1count() {
var chars = this.engraving.line1.length,
limit = 25;
return (limit - chars) + "/" + limit + " characters remaining";
},
line2count(){
var chars = this.engraving.line2.length,
limit = 25;
return (limit - chars) + "/" + limit + " characters remaining";
},
line3count(){
var chars = this.engraving.line3.length,
limit = 25;
return (limit - chars) + "/" + limit + " characters remaining";
},
line4count(){
var chars = this.engraving.line4.length,
limit = 25;
return (limit - chars) + "/" + limit + " characters remaining";
},
line5count(){
var chars = this.engraving.line5.length,
limit = 25;
return (limit - chars) + "/" + limit + " characters remaining";
}
},
How can I resuse this function to accept a data parameter and not repeat myself so much?
Share Improve this question asked Oct 11, 2017 at 17:23 Connor LeechConnor Leech 18.9k32 gold badges110 silver badges160 bronze badges 1- 2 This is the kind of thing that makes a great small ponent. – Bert Commented Oct 11, 2017 at 17:31
2 Answers
Reset to default 4You could use a method:
methods: {
linecount(line, limit) {
var chars = this.engraving.line[line].length,
return (limit - chars) + "/" + limit + " characters remaining";
},
}
And then in your html just reference it:
<p class='control'>
<span>{{ linecount(1,25) }}</span>
</p>
Typically for this kind of thing I would make a small ponent. The below example removes the validation (just to make the example easier) but works just like a regular input element.
The advantage of using ponents is things like the validation you want to do are scoped to the individual elements and they are easily re-usable.
console.clear()
Vue.ponent("engraving-line",{
props:["value", "placeholder", "limit"],
template:`
<div class='field is-grouped'>
<p class='control is-expanded'>
<input
class="input"
:placeholder="placeholder"
v-model='internalValue'>
</p>
<p class='control'>
<span>{{ lineCount }}</span>
</p>
</div>
`,
puted:{
internalValue:{
get() {return this.value},
set(v) {this.$emit("input", v)}
},
lineCount(){
return `${this.limit - this.value.length}/${this.limit} characters remaining`
}
}
})
new Vue({
el: "#app",
data:{
line1: "",
line2: "",
line3: "",
line4: "",
lineLimit: 25
}
})
<script src="https://unpkg./[email protected]"></script>
<div id="app">
<engraving-line :limit="lineLimit"
v-model="line1"
placeholder="Trophy engraving line 1 (25 character limit)">
</engraving-line>
<engraving-line :limit="lineLimit"
v-model="line2"
placeholder="Trophy engraving line 2 (25 character limit)">
</engraving-line>
<engraving-line :limit="lineLimit"
v-model="line3"
placeholder="Trophy engraving line 3 (25 character limit)">
</engraving-line>
<engraving-line :limit="lineLimit"
v-model="line4"
placeholder="Trophy engraving line 4 (25 character limit)">
</engraving-line>
</div>