How to define variable in vue template?
I've found a solution from some research, and I post answer myself, but not sure if there are any other best solutions.
Javascript snippet:
const Pass = {
render() {
return this.$scopedSlots.default(this.$attrs)
}
}
export default {
components: {
Pass
},
data: function () {
return {
vehicleTypeOptions: [],
}
},
methods: {
getVehicleData: function(vehicleType){
let option = _.find(this.vehicleTypeOptions, (obj)=>{
return obj.vehicleType==vehicleType;
});
return option;
},
loadData: function(){
// get data from server using API and set to vehicleTypeOptions
}
},
mounted: function(){
this.loadData();
}
}
Template snippet:
<Pass v-for="vehicleType in VehicleTypes" v-bind:key="vehicleType" :temp="getVehicleData(vehicleType)">
<div slot-scope="{temp}">
<div class="pannel">
<h6>{{ vehicleType }}</h6>
<p v-if="temp">
Cost per mile: <strong>${{ temp.costPerMile }}</strong>,
Cost per hour: <strong>${{ temp.costPerHour }}</strong>,
Cost per day: <strong>${{ temp.costPerDay }}</strong>
</p>
</div>
</div>
</Pass>
One option is to define a component. You can pass the value you need to "store" to it as a prop, and it can use it multiple ways. This is the more Vue-ish approach.
Another option is to wrap your function call in an array and use v-for
to create an alias for it. This is more of a hacky/lazy optimization, but it's not brittle, just odd to read.
new Vue({
el: '#app',
data: {
vehicleTypes: [0, 1]
},
methods: {
getVehicleTypeData(type) {
return [{
costPerMile: 10,
costPerHour: 40
}][type];
}
}
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<ul id="app" new>
<li v-for="vehicleType in vehicleTypes" :key="vehicleType">
<h3>{{ vehicleType }}</h3>
<template v-for="data in [getVehicleTypeData(vehicleType)]">
<div v-if="data">
{{ data.costPerMile }}<br> {{ data.costPerHour }}<br>
</div>
</template>
</li>
</ul>
A quick way to work around Vue's current shortcomings is to use scoping through v-for and a single loop. A hopefully explanatory example:
<v-list>
<v-list-tile v-for="(module, idx) in modules">
<template v-for="scope in [{ isLocked: someFunction(module)}]">
<!-- any markup -->
<v-list-tile-action v-if="scope.isLocked">
<v-icon color="amber">lock</v-icon>
</v-list-tile-action>
</template>
</v-list-tile>
</v-list>
The <template>
element above does the trick. You call your function (someFunction
) in a temporary size-1 array of objects, assign it to a property (isLocked
), which in turn is assigned to a scoped variable (scope
). You can now access whatever someFunction returns as many times as you like without sacrificing performance through scope.isLocked
.
You can just create a computed property which merges the type obj into the vehiclesTypes array.
computed: {
vehicles() {
return this.vehicleTypes.map(vehicle => {
return {
value: vehicle,
type: { ...this.getVehicleTypeData(vehicle) }
}
})
}
},
methods: {
getVehicleTypeData(vehicleType){
let options = _.find(this.vehicleTypeOptions, (obj)=>{
return obj.vehicleType==vehicleType;
});
return options;
}
}
And you can do:
<ul>
<li v-for="vehicle of vehicles" :key="vehicle.value">
<h3>{{ vehicle.value }}</h3>
<div v-if="vehicle.type">
{{ vehicle.type.costPerMile }}<br>
{{ vehicle.type.costPerHour }}<br>
</div>
</li>
</ul>
If you follow the logic I am sure it will work. Though I don't know the values of vehiclesTypes so the code above it may need some changes.
I hope it can help you.