Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vuetify Data Table Inline Filter

Please see this pretty Example by Dave Fontz on CodePen on how to archive Date Table Inline Filter and to be able to customize how to display headers and tableData rows of a vuetify v-data-table.

This worked like acharm for me with vuetify version below 2.

However since upgrading to vuetify version 2 the

<template slot="headers" slot-scope="props">

and

<template slot="items" slot-scope="props">

inside

<v-data-table>

seem to be ignored.

Anyone any suggestion on how to migrate Daves solution to be compatible with vuetify version 2?

Any Help or Hint is much appreciated!

Complete Code by Dave also below.

HTML:

<div id="app">
  <v-app id="inspire">
    <v-data-table
      v-model="selected"
      :headers="headers"
      :items="filteredDesserts"
      :pagination.sync="pagination"
      select-all
      item-key="name"
      class="elevation-1"
    >
      <template slot="headers" slot-scope="props">
        <tr>
          <th>
            <v-checkbox
              :input-value="props.all"
              :indeterminate="props.indeterminate"
              primary
              hide-details
              @click.native="toggleAll"
            ></v-checkbox>
          </th>
          <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>
        <tr class="grey lighten-3">
          <th>
            <v-icon>filter_list</v-icon>
          </th>
          <th
            v-for="header in props.headers"
            :key="header.text"
          >
            <div v-if="filters.hasOwnProperty(header.value)">
              <v-select flat hide-details small multiple clearable :items="columnValueList(header.value)" v-model="filters[header.value]">

              </v-select>

            </div>
          </th>
        </tr>
      </template>
      <template slot="items" slot-scope="props">
        <tr :active="props.selected" @click="props.selected = !props.selected">
          <td>
            <v-checkbox
              :input-value="props.selected"
              primary
              hide-details
            ></v-checkbox>
          </td>
          <td>{{ props.item.name }}</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>
        </tr>
      </template>
    </v-data-table>
  </v-app>
</div>

JS:

new Vue({
  el: '#app',
  data: () => ({
    pagination: {
      sortBy: 'name'
    },
    selected: [],
    headers: [
      {
        text: 'Dessert (100g serving)',
        align: 'left',
        value: 'name'
      },
      { text: 'Calories', value: 'calories' },
      { text: 'Fat (g)', value: 'fat' },
      { text: 'Carbs (g)', value: 'carbs' },
      { text: 'Protein (g)', value: 'protein' },
      { text: 'Iron (%)', value: 'iron' }
    ],
    filters: {
      fat: [],
      carbs: [],
      iron: [],
    },
    desserts: [
      {
        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%'
      }
    ]
  }),
  computed: {
    filteredDesserts() {
      return this.desserts.filter(d => {
        return Object.keys(this.filters).every(f => {
          return this.filters[f].length < 1 || this.filters[f].includes(d[f])
        })
      })
    }
  },

  methods: {
    toggleAll () {
      if (this.selected.length) this.selected = []
      else this.selected = this.desserts.slice()
    },
    changeSort (column) {
      if (this.pagination.sortBy === column) {
        this.pagination.descending = !this.pagination.descending
      } else {
        this.pagination.sortBy = column
        this.pagination.descending = false
      }
    },
    columnValueList(val) {
      return this.desserts.map(d => d[val])
    }
  }
})

See it in Action on CodePen

like image 371
timitalia Avatar asked Mar 04 '23 14:03

timitalia


1 Answers

I made a pen that filters columns, it's not exactly what you asked for, but it might give you an idea. It uses custom filtering from vuetify 2 documentation

HTML:

<div id="app">
  <v-app id="inspire">
    <template>
      <div>
        <v-data-table
          dense
          :headers="headers"
          :items="desserts"
          item-key="name"
          class="elevation-1"
          :search="search"
        >
          <template v-slot:body.prepend>
            <tr>
              <td>
                <v-text-field v-model="search" type="text" label="Dessert name"></v-text-field>
              </td>
              <td>
                <v-text-field v-model="calories" type="number" label="Less than"></v-text-field>
              </td>
               <td>
                <v-text-field v-model="fat" type="number" label="Less than"></v-text-field>
              </td>
              <td>
                <v-text-field v-model="carbs" type="number" label="Less than"></v-text-field>
              </td>
            </tr>
          </template>
        </v-data-table>
      </div>
    </template>
  </v-app>
</div>

and JS:

  new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data () {
      return {
        search: '',
        name: '',
        calories: '',
        fat:'',
        carbs:'',
        desserts: [
          {
            name: 'Frozen Yogurt',
            calories: 159,
            fat: 6.0,
            carbs: 24
          },
          {
            name: 'Ice cream sandwich',
            calories: 237,
            fat: 9.0,
            carbs: 37,

          },
          {
            name: 'Eclair',
            calories: 262,
            fat: 16.0,
            carbs: 23,

          },
          {
            name: 'Cupcake',
            calories: 305,
            fat: 3.7,
            carbs: 67,

          },
          {
            name: 'Gingerbread',
            calories: 356,
            fat: 16.0,
            carbs: 49,

          },
          {
            name: 'Jelly bean',
            calories: 375,
            fat: 0.0,
            carbs: 94,

          },
          {
            name: 'Lollipop',
            calories: 392,
            fat: 0.2,
            carbs: 98,

          },
          {
            name: 'Honeycomb',
            calories: 408,
            fat: 3.2,
            carbs: 87,

          },
          {
            name: 'Donut',
            calories: 452,
            fat: 25.0,
            carbs: 51,

          },
          {
            name: 'KitKat',
            calories: 518,
            fat: 26.0,
            carbs: 65,

          },
        ],
      }
    },
    computed: {
      headers () {
        return [
          {
            text: 'Dessert (100g serving)',
            align: 'left',
            sortable: false,
            value: 'name',
            filter: value => {
              if (!this.name) return true
              return value < value
            }
          },
          {
            text: 'Calories',
            value: 'calories',
            filter: value => {
              if (!this.calories) return true
              return value < parseInt(this.calories)
            }
          },
          { text: 'Fat (g)', value: 'fat',filter: value => {
              if (!this.fat) return true
              return value < parseInt(this.fat)
            }, },
          { text: 'Carbs (g)', value: 'carbs',
          filter: value => {
              if (!this.carbs) return true
              return value < parseInt(this.carbs)
            }
          }
        ]
      }
    }
})

I made a pen vuetify 2 data table column sort filter

like image 128
verunar Avatar answered Apr 02 '23 04:04

verunar