9
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Vuetify 2のv-data-tableでshow-selectを使いつつtrタグにclassを設定したい

Last updated at Posted at 2019-11-03

結論から

Vuetify 2.1.7で動作確認済みです。

<template>
  <v-data-table
    v-model="selected"
    :headers="headers"
    :items="items"
    item-key="id"
    show-select
  >
    <template v-slot:item="{ item, isSelected }">
      <tr :class="tableRowClass(item, isSelected)">
        <td>
          <v-simple-checkbox :value="isSelected" @input="toggleRow(item)" class="v-data-table__checkbox" hide-details />
        </td>
        <td>{{ item.id }}</td>
        <td>{{ item.name }}</td>
        <td>{{ item.status }}</td>
      </tr>
    </template>
  </v-data-table>
</template>
<script>
export default {
  data () {
    return {
      headers: [
        { text: 'id', value: 'id', sortable: false },
        { text: 'name', value: 'name', sortable: false },
        { text: 'status', value: 'status', sortable: false }
      ],
      selected: [],
    }
  },
  methods: {
    toggleRow (item) {
      if (this.selected.includes(item)) {
        // item が含まれていたら除去する
        this.selected = this.selected.filter(v => v !== item)
      } else {
        // item を追加する
        this.selected.push(item)
      }
    },
    tableRowClass (item, isSelected) {
      let klasses = []
      if (item.status != 'active') klasses.push('grey') // status が active だったら tr に grey クラスを追加する
      if (isSelected) klasses.push('v-data-table__selected') // checkbox が選択されていたら tr に v-data-table__selected クラスを追加する
      return klasses.join(' ')
    }
  }
}
</script>

背景

Vuetify 2.x の v-data-table では 1.5.x に比べて設定できる slot が増え、テーブルの表現力が格段に上がりました。
1.5.x までは <template slot="items" slot-scope="props"> と tbody 以下をまるっと書いていたものは <template v-slot:body="{ items }"><tbody><tr v-for="item in items" :key="item.id"><template v-slot:item="{ item }"> と書くことができたり、<template v-slot:item.name="{ value }"> と個別の td 内のみを書くことができるようになっています。
ですが、今回 show-select (チェックボックスでrowを選択できる機能) を使いつつ items の個々の item (要は tr タグ) に class を動的に追加したい要件が出てきて、いざ設定しようとしたときに、ドキュメントにそれっぽい slot も存在しないし、ソースコードを見てもいい感じに設定できそうな書き方が思い付かず、どうやって追加したらいいものか結構悩みました。やっと解決できたので、覚書として記事に残します。

解決まで

最初は vuetify 2 data-table row show-select checkbox と Google で検索して出てきた
https://stackoverflow.com/questions/57671044/select-all-rows-of-a-vuetify-data-table-with-custom-table-body-implementation
↑この記事を参考に書き始めましたが、上手く行きませんでした。
以下に抜粋します。

<v-data-table v-model="selectedTasks" :headers="headers" :items="tasks" item-key="id" show-select>
  <template v-slot:body="{ items }">
    <tbody>
      <tr v-for="item in items" :key="item.id">
        <td>
          <v-checkbox v-model="selectedTasks" :value="item" style="margin:0px;padding:0px" hide-details />
        </td>
        <td>{{ item.text }}</td>
        <td>
          <v-btn text icon x-small>
            Edit
          </v-btn>
        </td>
      </tr>
    </tbody>
  </template>
</v-data-table>
...
<script>
data() {
  selectedTasks: []
}
</script>

上手く行かなかった点としては、

  • v-checkboxの :value に item を指定しておいて、チェックボックスを押下すると、v-model の selectedTasks に要素が追加されます(ここまでは問題なし)。この後v-paginationなどでテーブルのitemsが変化すると、selectedTasksには要素が一つしか無いにも関わらず、表示されたitemsが全て選択された(チェックボックスがチェック済みになっている)状態になっていた。
  • (気持ちの問題かもしれませんが、) style属性でmargin、paddingを設定するのがちょっと嫌だな…と。

これらの問題については、なぜそうなるのか詳しいところまで調べてはいません。

解決のポイントは

  • <template v-slot:item="{ item, isSelected }">
    • item slot を使う。
    • body だと row ごとの isSelected を取れない。
  • <v-simple-checkbox :value="isSelected" @input="toggleRow(item)" class="v-data-table__checkbox" hide-details />
    • v-checkbox ではなくて v-simple-checkbox を使う。
    • v-checkbox だと、前後に (余計なタグやclassが挿入されてしまうため) margin や padding を調整しなければならない。
    • v-simple-checkbox なら v-simple-checkbox class のみの div タグが設定されて magin や padding の指定が不要。 class="v-data-table__checkbox" は Vuetify のソースコードでは付与しているので追加してみたが、特に表示上は有っても無くても変わらない模様。
    • <v-checkbox v-model="selectedTasks" :value="item"> で上手くいきそうな気がするが、上記の items が全て選択された(意図しない)状態になる問題が発生する。
    • v-simple-checkbox の value に boolean を返す isSelected を指定して、 input イベントで selected に item を toggle する method を発火させる。

ざっくりとこんな感じです。

もしかしたら他に slot を上手く使うもっといい方法があるのかもしれませんので、詳しい方がいらっしゃったら是非コメントを頂きたいです m(_ _)m

9
9
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
9
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?