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.