I'm working with a portfolio project, where users can upload a picture, provide a description below it, and then click the "add" button to add another image and description.
I'm trying to add a character counter to the description input, which is a textarea
field. Usually I can add the name of the v-model
into the function, and it works fine, but this textarea
is in a for
-loop, so I'm not sure how to get this function to work.
Template:
<div class="newPortfolioList">
<div class="newPortfolioItem" v-for="(item, index) in this.portfolioItems" v-bind:key="index">
....
<div class="newPortfolioDescription">
<textarea v-model="item.portfolioDescription" @keyup='remaincharCount()' maxlength="1000" placeholder="Item Description..."></textarea>
</div>
<!-- Displaying the remaining characters -->
<span style="text-align:left; padding: 10px;">{{ remaincharactersText }}</span>
</div>
...
Script:
export default {
data () {
return {
portfolioItems:[],
maxcharacter: 1000,
remaincharactersText: "1000 characters remaining"
}
},
methods: {
createPortfolioItem () {
this.portfolioItems.push({
portfolioDescription: ''
})
},
remaincharCount () {
if (this.foo.length > this.maxcharacter) {
this.remaincharactersText = "Exceeded "+this.maxcharacter+" characters limit.";
} else {
var remainCharacters = this.maxcharacter - this.foo.length;
this.remaincharactersText = remainCharacters + " characters remaining";
}
}
}
}
You should be aware that the textarea already has its maxlength
set to 1000, so the label Exceeded N characters limit
isn't possible (unless you check for fewer than 1000). Currently, the label always would display N reminaing characters
.
Instead of storing the character count (unnecessarily taking up extra memory), you could display the calculation inline with string interpolation:
<template>
<div>
<textarea v-model="item.portfolioDescription" maxlength="1000"></textarea>
<span>{{ 1000 - item.portfolioDescription.length }} remaining characters</span>
</div>
</template>
If you prefer storing the character count (e.g., for some internal processing), you could add a new property to the item data:
<script>
const MAXLEN = 1000
export default {
methods: {
createPortfolioItem() {
this.portfolioItems.push({
remainChars: MAXLEN, // <--
})
},
}
}
</script>
Then, update item.remainChars
upon the textarea
's input
-event, and display item.remainChars
inline.
<template>
<div>
<textarea v-model="item.portfolioDescription" maxlength="1000"
@input="item.remainChars = 1000 - item.portfolioDescription.length">
</textarea>
<span>{{ item.remainChars }} remaining characters</span>
</div>
</template>
You could compute the character-count labels in a separate array that corresponds to portfolioItems
:
<script>
const MAXLEN = 1000
export default {
computed: {
remainingCharsText() {
return this.portfolioItems.map(item => `${MAXLEN - item.portfolioDescription.length} remaining characters`)
},
}
}
</script>
Then, update your template to reference this computed array by index
:
<template>
<div>
<textarea v-model="item.portfolioDescription" maxlength="1000">
</textarea>
<span>{{ remainingCharsText[index] }}</span>
</div>
</template>