Reputation: 729
I have a loop, where I need to evaluate the same process in several HTML elements. It looks like this:
<template v-for="(week, wix) in weeks">
<td v-for="(day, dix) in week.Days" :class="{delDate : moment(order.DeliveryDate).diff(moment(day.Date), 'days') == 0}">
<v-icon v-if="dix==0 && wix==0 && moment(order.DeliveryDate).diff(moment(day.Date), 'days') < 0">fa-chevron-left</v-icon>
<v-icon v-if="dix==6 && wix==1 && moment(order.DeliveryDate).diff(moment(day.Date), 'days') > 0">fa-chevron-right</v-icon>
</td>
</template>
As you can see, I calculate the difference between 2 dates 3 times to evaluate the same value.
In a programming language, I'd just put the result in a variable, and use it in all 3 places, but can this be done somehow in Vue?
Is the best way to separate those inner <td>
in its own component? and then calculate it once in a container template?
Upvotes: 1
Views: 277
Reputation: 4246
You can create a method under your data methods property like this:
data: {
methods: {
calculateDifference(order, day) {
return moment(order.DeliveryDate).diff(moment(day.Date), 'days');
}
}
}
If you want to cache result for same input parameters, you can use computed like this:
data: {
computed: {
calcDifference() {
return (order, day) => {
window.iterations++
return moment(order.DeliveryDate).diff(moment(day.Date), 'days')
}
},
},
},
And then it can be used in your template:
<template v-for="(week, wix) in weeks">
<td v-for="(day, dix) in week.Days" :class="{delDate : calculateDifference(order, day) == 0}">
<v-icon v-if="dix==0 && wix==0 && calculateDifference(order, day) < 0">fa-chevron-left</v-icon>
<v-icon v-if="dix==6 && wix==1 && calculateDifference(order, day) > 0">fa-chevron-right</v-icon>
</td>
</template>
Upvotes: 1
Reputation: 138696
I recommend computing a new array that contains the pre-calculated dates (move the calculation from the template into a computed property, e.g., named myWeeks
):
export default {
//...
computed: {
myWeeks() {
return this.weeks.map((week, weekIndex) => {
return {
...week,
myDays: week.Days.map((day, dayIndex) => {
const deliveryDueDate = deliveryDate.diff(moment(day.Date), 'days')
return {
...day,
onDelivery: deliveryDueDate === 0,
beforeDelivery: (dayIndex === 0 && weekIndex === 0) && (deliveryDueDate < 0),
afterDelivery: (dayIndex === 6 && weekIndex === 1) && (deliveryDueDate > 0),
}
})
}
})
}
}
}
Then in your template, you could use the computed myWeeks
without calculation clutter:
<template v-for="week in myWeeks">
<td v-for="day in week.myDays" :class="{delDate: day.onDelivery}">
<v-icon v-if="day.beforeDelivery">fa-chevron-left</v-icon>
<v-icon v-if="day.afterDelivery">fa-chevron-right</v-icon>
</td>
</template>
Upvotes: 1