Select all rows of a Vuetify data table with custom table body implementation
Asked Answered
S

1

15

I can't figure how to implement the select all option for my data-table using Vuetify v2 when I have a custom implementation for the slot body.

Here is a little example:

<template>
  <v-card
    max-width="300"
    class="pa-6"
  >
    <v-data-table
      :items="tasks"
      :headers="headers"
      show-select
      dense
    >
      <template v-slot:body="{ items }">
        <tbody>
          <tr
            v-for="item in items"
            :key="item.id"
          >
            <td>
              <v-checkbox
                v-model="selectedTasks"
                :value="item.id"
                style="margin:0px;padding:0px"
                hide-details
              />
            </td>
            <td>{{ item.text }}</td>
            <td>
              <v-btn
                text
                icon
                x-small
              >
                <v-icon>pageview</v-icon>
              </v-btn>
            </td>
          </tr>
        </tbody>
      </template>
    </v-data-table>
  </v-card>
</template>
<script>
export default {
  data() {
    return {
      headers: [
        { text: 'task', value: 'text' },
        { text: 'actions' }
      ],
      selectedTasks: []
    }
  },
  computed: {
    tasks() {
      return [
        { id: 1, text: 'Collect packets' },
        { id: 2, text: 'Buy bread' }
      ]
    }
  }
}
</script>

Which produces the following data table:

enter image description here

Now I want to implement that when the checkbox "all" is selected (like above in the picture), it selects all the rows of my table.

The doc says to implement the slot header.data-table-select to customise the select all button, and I could find the example below in the examples about slots for the data-table.

<template v-slot:header.data-table-select="{ on , props }">
    <v-simple-checkbox
       color="purple"
       v-bind="props"
       v-on="on"
    />
</template>

However, I can't make it to select all the rows when I check this box. I didn't find any example on how to implement the select all with a "custom" table body. Hopefully, someone can help me here. Thanks in advance

Stout answered 27/8, 2019 at 8:56 Comment(0)
M
24

Data table v-model needs to be set to selectedItems and check box for selecting needs to have value of item collection.

<!DOCTYPE html>
<html>

<head>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>

<body>
<div id="app">
    <v-app>
        <v-content>
            <v-container>
                <h2>Data Table</h2>

                <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>
                <v-btn v-on:click="addTask()">Add Task</v-btn>
            </v-container>
        </v-content>
    </v-app>
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>
<script>
    new Vue({
        el: '#app',
        vuetify: new Vuetify(),

        data() {
            return {
                headers: [
                    {
                        text: 'Task',
                        value: 'text'
                    },
                    {
                        text: 'Actions'
                    }
                ],
                tasks: [
                    {
                        id: 1,
                        text: 'Collect packets'
                    },
                    {
                        id: 2,
                        text: 'Buy bread'
                    }
                ],
                selectedTasks: []
            }
        },
        methods: {
            addTask() {
                this.tasks = this.tasks.map(t => ({...t}))
                this.tasks.push({id: this.tasks.length + 1, text: 'New Task'});

                this.selectedTasks = this.selectedTasks.map(t => {
                    return this.tasks.find(e => e.id == t.id) || t;
                })
            }
        }
    })
</script>
</body>

</html>
Madonna answered 27/8, 2019 at 11:58 Comment(6)
Thanks a ton. I was sort of looking for this solutions, finally I found this.Dentist
Hi, I've just checked and it does work with pagination, can you provide more info how did you test ?Madonna
When items change after an API call, the boxes tick automatically.Hendecagon
Just resync selectedTasks using model id'sMadonna
@EdinOmeragic can you elaborate on how to do this resync? Your example works for me but after an API call I have the same issue where all the checkboxes are checkedAffected
I've updated example, note that after updating tasks, selectedTasks are also updated to contain object instances from tasks collection matched by idMadonna

© 2022 - 2024 — McMap. All rights reserved.