Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Computed properties in Vuetify Datatable rows

I am using Vuetify and Vuetify/Datatables for a website. Now I want some computed properties on every row of the table.

To do that I would probably need to make a component of the <template> element and add computed properties to that component. I tried <template is="myComponent" :m="props.item"> but this did not work.

<v-data-table
  :headers="headers"
  :items="items"
  hide-actions
  class="elevation-1"
>
  <template slot="items" slot-scope="props">
    <td>{{ THIS_VALUE_COMPUTED }}</td>
    <td class="text-xs-right">{{ props.item.calories }}</td>
    <td class="text-xs-right">{{ props.item.fat }}</td>
    <td class="text-xs-right">{{ props.item.carbs }}</td>
    <td class="text-xs-right">{{ props.item.protein }}</td>
    <td class="text-xs-right">{{ props.item.iron }}</td>
  </template>
</v-data-table>
like image 566
Hendrik Jan Avatar asked Mar 10 '18 21:03

Hendrik Jan


2 Answers

it's a bit aged question but this might work, it is from the vuetify 2.0.19 documentation. Here you can do a computed value on one of the single properties of your table.

<v-data-table
  :headers="headers"
  :items="items"
  hide-actions
  class="elevation-1"
>
   <template
            v-slot:item.calories="{ item }" >
    {{ THIS_VALUE_COMPUTED }}
  </template>
</v-data-table>
like image 167
Alex Avatar answered Nov 20 '22 00:11

Alex


I was able to use computed properties by including an extra component (with computed properties) and an extra <template> element. I am not realy happy with havign two <template> elements inside each other but this was the only way to get this working. Any better solutions are still very welcome.

(Working codepen example)

JS (a modification on the Vuetify Datatable example):

let myComponent = Vue.component('my-component', {
  props: {
    item: {
      type: Object,
      required: true,
    }
  },
  mounted: function() {
    console.log('mounted', this.item)
  },
  computed: {
    COMPUTED_PROPERTY: function() {
      return this.item.fat +
        this.item.carbs +
        this.item.protein
    }
  },
  template: `<tr>
    <td>{{ item.name }}</td>
    <td>{{ item.calories }}</td>
    <td>{{ COMPUTED_PROPERTY }}</td>
    <td>{{ item.iron }}</td>
  </tr>`
})

new Vue({
  el: '#app',
  mounted: function() {
    console.log('loaded')
  },
  components: { myComponent },
  data: () => ({
    pagination: {
      sortBy: 'name'
    },
    selected: [],
    headers: [
      {
        text: 'Dessert (100g serving)',
        align: 'left',
        value: 'name'
      },
      { text: 'Calories', value: 'calories' },
      { text: 'Fat + Carbs + Protein (g)', value: 'total' },
      { text: 'Iron (%)', value: 'iron' }
    ],
    items: [
      {
        value: false,
        name: 'Frozen Yogurt',
        calories: 159,
        fat: 6.0,
        carbs: 24,
        protein: 4.0,
        iron: '1%'
      },
      {
        value: false,
        name: 'Ice cream sandwich',
        calories: 237,
        fat: 9.0,
        carbs: 37,
        protein: 4.3,
        iron: '1%'
      },
      {
        value: false,
        name: 'Eclair',
        calories: 262,
        fat: 16.0,
        carbs: 23,
        protein: 6.0,
        iron: '7%'
      },
      {
        value: false,
        name: 'Cupcake',
        calories: 305,
        fat: 3.7,
        carbs: 67,
        protein: 4.3,
        iron: '8%'
      },
      {
        value: false,
        name: 'Gingerbread',
        calories: 356,
        fat: 16.0,
        carbs: 49,
        protein: 3.9,
        iron: '16%'
      },
      {
        value: false,
        name: 'Jelly bean',
        calories: 375,
        fat: 0.0,
        carbs: 94,
        protein: 0.0,
        iron: '0%'
      },
      {
        value: false,
        name: 'Lollipop',
        calories: 392,
        fat: 0.2,
        carbs: 98,
        protein: 0,
        iron: '2%'
      },
      {
        value: false,
        name: 'Honeycomb',
        calories: 408,
        fat: 3.2,
        carbs: 87,
        protein: 6.5,
        iron: '45%'
      },
      {
        value: false,
        name: 'Donut',
        calories: 452,
        fat: 25.0,
        carbs: 51,
        protein: 4.9,
        iron: '22%'
      },
      {
        value: false,
        name: 'KitKat',
        calories: 518,
        fat: 26.0,
        carbs: 65,
        protein: 7,
        iron: '6%'
      }
    ]
  }),

  methods: {
    changeSort (column) {
      if (this.pagination.sortBy === column) {
        this.pagination.descending = !this.pagination.descending
      } else {
        this.pagination.sortBy = column
        this.pagination.descending = false
      }
    }
  }
})

HTML:

<div id="app">
<v-app id="inspire">
  <v-data-table
    v-model="selected"
    :headers="headers"
    :items="items"
    select-all
    :pagination.sync="pagination"
    item-key="name"
    class="elevation-1"
  >
    <template slot="headers" slot-scope="props">
      <tr>
        <th
          v-for="header in props.headers"
          :key="header.text"
          :class="['column sortable', pagination.descending ? 'desc' : 'asc', header.value === pagination.sortBy ? 'active' : '']"
          @click="changeSort(header.value)"
        >
          <v-icon small>arrow_upward</v-icon>
          {{ header.text }}
        </th>
      </tr>
    </template>
    <template slot="items" slot-scope="props">
      <template :active="props.selected" @click="props.selected = !props.selected">
        <my-component :item="props.item">
        </my-component>
      </template>
    </template>
  </v-data-table>
</v-app>
</div>
like image 39
Hendrik Jan Avatar answered Nov 20 '22 00:11

Hendrik Jan