Vuetify.jsのData tablesでフィルタリングを行う

Vuetify.jsのData tablesはフィルタリングするための設定ができるのですが、設定項目にfilter、custom-filter、searchが存在していて、何が何だかよくわからん、となってしまったのでソースコードを読みつつ確認してみした。

# それぞれの要素に関するざっくりとした解説
## search
これは、フィルタリングを行うためのデータを指定します。
フィルタリングに利用するキーワードが固定的なら文字列を、ユーザによる入力を行う場合は入力値を格納する変数をバインドします。

## filter
フィルタリングを行うための処理を指定します。戻り値はbooleanで、表示する場合はtrue、しない場合はfalseを返却するようにします。
custom-filterになにも指定していない場合は以下のような処理となります。

```javascript
(items, search, filter, headers) => {
  search = search.toString().toLowerCase()
  if (search.trim() === '') return items
  const props = headers.map(h => h.value)
  return items.filter(item => props.some(prop => filter(getObjectValueByPath(item, prop), search)))
}
```
まず、headersからvalue要素の値を抽出します。
その後、各行に該当するデータに対して、先ほど抽出した値をキーとする値に対して、filter処理を呼び出しています。

なお、filterに何も指定しない場合は以下のような処理が行われます。

```javascript
(val, search) => {
  return val != null &&
    typeof val !== 'boolean' &&
    val.toString().toLowerCase().indexOf(search) !== -1
}
```
つまり、searchのみを指定した場合は、指定された文字列を含んでいる行のみ出力します。
このとき、大文字と小文字は区別されません。

## custom-filter
filterのところに記載した通り、デフォルトではすべての要素に対してfilter処理を行っています。
これを変更したい場合は、custom-filterに処理を指定することができます。

# 例

### 基本的なパターン。フィルタリングする値は固定値。
出身地が大阪府の人のみ表示しています。

```vue:table.vue
<template>
  <v-app>
    <v-container>
      <v-data-table :items="item" :headers="header" class="elevation-10" :filter="filter" search="大阪府">
        <template slot="items" slot-scope="row">
          <td>{{row.item.name}}</td>
          <td>{{row.item.score}}</td>
          <td>{{row.item.birthplace}}</td>
        </template>
      </v-data-table>
    </v-container>
  </v-app>
</template>

<script>
export default {
  name: "table",
  methods: {
    filter(val, search) {
      return val === search;
    }
  },
  data() {
    return {
      header: [
        { text: "名前", value: "name" },
        { text: "点数", value: "score" },
        { text: "出身地", value: "birthplace" }
      ],
      item: [
        { name: "柴山はるみ", score: 51, birthplace: "大阪府" },
        { name: "岡田雅彦", score: 48, birthplace: "宮崎県" },
        { name: "若槻建", score: 67, birthplace: "長野県" },
        { name: "宮下詩織", score: 23, birthplace: "大阪府" },
        { name: "車慎之介", score: 43, birthplace: "岡山県" },
        { name: "武藤里穂", score: 79, birthplace: "大阪府" },
        { name: "金子宏行", score: 82, birthplace: "神奈川県" },
        { name: "草野彩華", score: 12, birthplace: "静岡県" },
        { name: "海音寺薫", score: 45, birthplace: "群馬県" },
        { name: "堤咲", score: 100, birthplace: "兵庫県" }
      ]
    };
  }
};
</script>
```

### フィルタリングする値をユーザに入力させるパターン
フィルタリングする値をユーザに入力させる場合には、テキストフィールドを定義しv-modelでバインドします。
バインドした値をsearchに指定すれば、入力した値でバインドすることができます。

```vue:table.vue
<template>
  <v-app>
    <v-container>
      <v-text-field append-icon="search" label="Search" single-line hide-details v-model="search"></v-text-field>
      <v-data-table :items="item" :headers="header" class="elevation-10" :filter="filter" :search="search">
        <template slot="items" slot-scope="row">
          <td>{{row.item.name}}</td>
          <td>{{row.item.score}}</td>
          <td>{{row.item.birthplace}}</td>
        </template>
      </v-data-table>
    </v-container>
  </v-app>
</template>

<script>
export default {
  name: "table",
  methods: {
    filter(val, search) {
      return val === search;
    }
  },
  data() {
    return {
      search: "",
      // ～～先ほどの例と同様のheaderとitemを定義するため省略～～
    };
  }
};
</script>
```

### custom-filterを利用するパターン
先ほどの例では、デフォルトのcustom-filterが適用されます。
そのため、出身地以外のフィールドに対しても判定処理が行われてしまいます。
例えば、点数が入力された値以上の人を表示するために、filterを以下のように書き換えたとします。

```js
filter(val, search){
  return val >= search;
}
```

実際に試してみるとわかりますが、これでは何もフィルタリングされません。
名前などのフィールドに対しても比較処理が実行されてしまい、思った通りの処理にはなりません。
ここでcustom-filterを利用します。

```vue:table.vue
<template>
  <v-app>
    <v-container>
      <v-text-field append-icon="search" label="Search" single-line hide-details v-model="search"></v-text-field>
      <v-data-table :items="item" :headers="header" class="elevation-10" :filter="filter" :search="search" :customFilter="customFilter">
        <template slot="items" slot-scope="row">
          <td>{{row.item.name}}</td>
          <td>{{row.item.score}}</td>
          <td>{{row.item.birthplace}}</td>
        </template>
      </v-data-table>
    </v-container>
  </v-app>
</template>

<script>
export default {
  // 前回までのサンプルと同様なのでいろいろ省略
  methods:{
    filter(val, search){
      return val >= search;
    },
    customFilter(items, search, filter){
      return items.filter(item => filter(item.score, search);
    }
  }

  // 前回までのサンプルと同様なのでいろいろ省略
}
</script>
```

上記の例ではfilterも定義していますが、custom-filter側で全部やってしまってもいいような気がします。