LoginSignup
8
7

More than 3 years have passed since last update.

[Vuetify] V-Data-Table で複数項目のフィルタリングを行う方法

Posted at

目的

本記事の目的は、Vuetifyの<v-data-table>を使用して、複数条件で絞り込み、動的にテーブルの表示を切り替えることである。

やったこと

はじめにVuetifyのV-Data-TableのAPI を読んで、custom-filterプロパティを使用しようと考えた。
しかし、custom-filterプロパティの引数であるsearchは一つしか変数を持つことができない。
スクリーンショット 2021-02-06 17.42.23.png
そこで、V-Data-TableのAPIのheadersに記述されているfilterプロパティを使用することで複数項目のフィルタリングを可能にした。
スクリーンショット 2021-02-06 17.45.56.png

作成画面

スクリーンショット 2021-02-06 16.56.32.png

使用環境

  • Vue.js: "^2.6.11",
  • Vue-Router: "^3.2.0",
  • Vuetify: "^2.3.21"

ファイルの説明

  • sampleDataTable.json : テーブルに格納するサンプルデータ
  • Table.vue : テーブルを表示させる為のVueファイル

ソースコード

sampleDataTable.json
{
  "data": [
    {
      "name": "Frozen Yogurt",
      "calories": 159,
      "fat": 6.0,
      "carbs": 24,
      "protein": 4.0,
      "iron": "1%"
    },
    {
      "name": "Ice cream sandwich",
      "calories": 237,
      "fat": 9.0,
      "carbs": 37,
      "protein": 4.3,
      "iron": "1%"
    },
    {
      "name": "Eclair",
      "calories": 262,
      "fat": 16.0,
      "carbs": 23,
      "protein": 6.0,
      "iron": "7%"
    },
    {
      "name": "Cupcake",
      "calories": 305,
      "fat": 3.7,
      "carbs": 67,
      "protein": 4.3,
      "iron": "8%"
    },
    {
      "name": "Gingerbread",
      "calories": 356,
      "fat": 16.0,
      "carbs": 49,
      "protein": 3.9,
      "iron": "16%"
    },
    {
      "name": "Jelly bean",
      "calories": 375,
      "fat": 0.0,
      "carbs": 94,
      "protein": 0.0,
      "iron": "0%"
    },
    {
      "name": "Lollipop",
      "calories": 392,
      "fat": 0.2,
      "carbs": 98,
      "protein": 0,
      "iron": "2%"
    },
    {
      "name": "Honeycomb",
      "calories": 408,
      "fat": 3.2,
      "carbs": 87,
      "protein": 6.5,
      "iron": "45%"
    },
    {
      "name": "Donut",
      "calories": 452,
      "fat": 25.0,
      "carbs": 51,
      "protein": 4.9,
      "iron": "22%"
    },
    {
      "name": "KitKat",
      "calories": 518,
      "fat": 26.0,
      "carbs": 65,
      "protein": 7,
      "iron": "6%"
    }
  ]
}

Table.vue
<template>
  <v-data-table :headers="headers" :items="desserts" item-key="name" class="elevation-1 pa-6">
    <template v-slot:top>

      <v-container fluid>
        <v-row>

          <v-col cols="4">
            <v-row class="pa-6">
              <!-- Filter for Desert -->
              <v-text-field
                v-model="dessertFilterValue"
                type="text"
                label="Desert Name">
              </v-text-field>
            </v-row>
          </v-col>

          <v-col cols="4">
            <v-row class="pa-6">
              <!-- Filter for Calories -->
              <v-select
                :items="caloriesList"
                v-model="caloriesFilterValue"
                label="Calories"
              ></v-select>

            </v-row>
          </v-col>

          <v-col cols="4">
            <v-row class="pa-6">
              <!-- Filter for Fat-->
              <v-text-field
                v-model="FatFilterValue"
                type="text"
                label="Fat">
              </v-text-field>
            </v-row>
          </v-col>

        </v-row>
      </v-container>

    </template>
  </v-data-table>
</template>

<script>
  // Table info.
  import tableData from './sampleDataTable';
  export default {
    name: 'Table',
    data() {
      return {
        // We need some values for our select.
        caloriesList: [
          {text: "All", value: null},
          {text: "Only 237", value: 237},
          {text: "Only 305", value: 305},
        ],
        // Filter models.
        dessertFilterValue: '',
        FatFilterValue: '',
        caloriesFilterValue: null,
        // Table data.
        desserts: tableData.data,
      }
    },
    computed: {
      headers() {
        return [
          {
            text: 'Dessert (100g serving)',
            align: 'left',
            sortable: false,
            value: 'name',
            filter: this.nameFilter,
          },
          {
            text: 'Calories',
            value: 'calories',
            filter: this.caloriesFilter,
          },
          {
            text: 'Fat (g)',
            value: 'fat',
            filter: this.FatFilter,
          },
          {text: 'Carbs (g)', value: 'carbs'},
          {text: 'Protein (g)', value: 'protein'},
          {text: 'Iron (%)', value: 'iron'},
        ]
      },
    },
    methods: {
      nameFilter(value) {
        // this.dessertFilterValue がなければフィルタリングしない
        if (!this.dessertFilterValue) {
          return true
        }
        return value.toLowerCase().includes(this.dessertFilterValue.toLowerCase());
      },
      caloriesFilter(value) {
        if (!this.caloriesFilterValue) {
          return true
        }
        return value === this.caloriesFilterValue
      },
      FatFilter(value) {
        if(!this.FatFilterValue) {
          return true
        }
        return value === parseInt(this.FatFilterValue)
      }
    }
  }
</script>

上記のコードは、

Vuetifyの<v-text-field>を使用して、

<v-text-field
  v-model="dessertFilterValue"
  type="text"
  label="Desert Name">
</v-text-field>

のようにv-modelを定義する。
また下記のように、Vue.jsのdataプロパティにv-modelの初期値を定義する。

dessertFilterValue: '',
FatFilterValue: '',
caloriesFilterValue: null,

そして、computed() の headers() の各テーブルの項目内でfilterプロパティを定義する。

computed: {
      headers() {
        return [
          {
            text: 'Dessert (100g serving)',
            align: 'left',
            sortable: false,
            value: 'name',
            filter: this.nameFilter,
          },
          {
            text: 'Calories',
            value: 'calories',
            filter: this.caloriesFilter,
          },
          {
            text: 'Fat (g)',
            value: 'fat',
            filter: this.FatFilter,
          },
          {text: 'Carbs (g)', value: 'carbs'},
          {text: 'Protein (g)', value: 'protein'},
          {text: 'Iron (%)', value: 'iron'},
        ]
      },
   },

最後に、methodsの各関数でフィルタリングすることでテーブルの表示を切り替えることができる。
例えばDesert Nameでフィルタリングをかけたい場合、

nameFilter(value) {
        // this.dessertFilterValue がなければフィルタリングしない
        if (!this.dessertFilterValue) {
          return true
        }
        return value.toLowerCase().includes(this.dessertFilterValue.toLowerCase());
      },

とすることで、v-modelが変化するたびに動的にテーブルの表示を切り替えることが可能になる。

結論

簡潔かつシンプルにフィルタリングできるVuetifyは凄い!!!

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7