1👍
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
.
Option 1: Display count calculation inline
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>
Option 2: Display count from item variable
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>
Option 3: Display computed text
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>
2👍
There are a number of ways you could do this.
In this case I think your best option is to introduce a new component to represent a single portfolio item. Each of these components can manage their own message. From their perspective there is no loop to consider.
So you’d have something like this for your list template:
<div class="newPortfolioList">
<my-new-portfolio-item
v-for="(item, index) in portfolioItems"
:key="index"
:portfolio-item="item"
/>
</div>
Two side notes. I’ve dropped the v-bind
prefix on your key, a :
will suffice. I’ve also removed the this.
before portfolioItems
as that’s also unnecessary. The Vue linting rules can be used to help keep this stuff in check.
There are alternatives to introducing a new component. You could generate the value of remaincharactersText
within the template rather than keeping it in state. It could still be a method call but it wouldn’t be precalculated. Something like this:
<span style="text-align:left; padding: 10px;">{{ remaincharCount(item) }}</span>
A further (even more painful) alternative would be to make remaincharactersText
an array of values and then grab the relevant one by index:
<span style="text-align:left; padding: 10px;">{{ remaincharactersText[index] }}</span>
But, to reiterate, introducing a separate component for the items within the v-for
is probably the best way to go here.