Vuetify: Show pagination controls at the top of my v-data-table as well as in the footer
Asked Answered
B

2

8

The v-data-table has a top slot, with a pagination prop whose structure matches that of the footer slot. Is it possible to assign the top slot to reference the same (presumably a v-pagination) control that the footer is using?

My goal here is to duplicate the pagination controls (that are in the footer) at the top of the table.

Babbette answered 15/1, 2020 at 21:40 Comment(0)
K
29

In fact, controls shown by default in v-data-table footer slot is normal (public - not internal) Vuetify component v-data-footer. You can add it into the top slot easily like this:

<div id="app">
  <v-app id="inspire">
    <v-data-table
      v-model="selected"
      :headers="headers"
      :items="desserts"
      :items-per-page="5"
      :single-select="true"
      item-key="name"
      show-select
      class="elevation-1"
    >
      <template v-slot:top="{ pagination, options, updateOptions }">
        <v-data-footer 
          :pagination="pagination" 
          :options="options"
          @update:options="updateOptions"
          items-per-page-text="$vuetify.dataTable.itemsPerPageText"/>
      </template>
    </v-data-table>
  </v-app>
</div>

Demo

Kassandra answered 29/1, 2020 at 19:29 Comment(4)
That is EXACTLY what I was looking for. I didn't want to reinvent the wheel, but couldn't find an example of this. Thanks!Babbette
To get this to work with v-data-iterator, use v-slot:header instead of v-slot:top.Windowshop
To remove the old footer from showing you need to add hide-default-footerTomkins
@EbrahimKaram Good tip, but my intent was to show pagination controls in both the header and footer.Babbette
T
1

Will it work if it uses v-paginate component? Here is a working example on codepen.

https://codepen.io/v08i/pen/JjoVmVR

<div id="app">
  <v-app id="inspire">
     <v-card>
       <v-btn color="primary" @click="dialog = true">Open Dialog</v-btn>
       <v-dialog v-model="dialog" :fullscreen="fullScreen" transition="dialog-bottom-transition" :overlay=false
scrollable>
      <v-card>
          <v-toolbar style="flex: 0 0 auto;" dark class="primary">
          <v-btn icon @click.native="dialog = false" dark>
            <v-icon>close</v-icon>
          </v-btn>
          <v-toolbar-title>Data</v-toolbar-title>
          <v-spacer></v-spacer>
        </v-toolbar>
        <v-card-text>
          <v-card-title>
        Nutrition
        <v-spacer></v-spacer>
        <v-text-field
          :append-icon="search?'close':'search'"
          :append-icon-cb="() => (search = '')"
          @keydown.native.escape="search=''"
          label="Search"
          single-line
          hide-details
          v-model="search"
        ></v-text-field>
      </v-card-title>
    <div>
          <v-pagination v-model="pagination.page" :length="pages"></v-pagination>
      <v-data-table
        v-bind:headers="headers"
        v-bind:items="items"
        v-bind:search="search"
        v-bind:pagination.sync="pagination"
        hide-actions
        class="elevation-1"
      >
        <template slot="header" scope="props">
        </template>
        <template slot="headerCell" scope="props">
          <v-tooltip bottom>
            <span slot="activator">
              {{ props.header.text }}
            </span>
            <span>
              {{ props.header.text }}
            </span>
          </v-tooltip>
        </template>
        <template slot="items" scope="props">
          <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.sodium }}</td>
          <td  class="text-xs-right">{{ props.item.calcium }}</td>
          <td  class="text-xs-right">{{ props.item.iron }}</td>
        </template>
      </v-data-table>
      <div class="text-xs-center pt-2">
        <v-pagination v-model="pagination.page" :length="pages"></v-pagination>

        </v-card-text>

          <div style="flex: 1 1 auto;"></div>
      </v-card>

    </v-dialog>


        </v-card>


  </v-app>
</div>

new Vue({
  el: '#app',
  data () {
    return {
      dialog: false,
      fullScreen: true,
      search: '',
      pagination: {},
      selected: [],
      headers: [
        {
          text: 'Dessert (100g serving)',
          align: 'left',
          sortable: false,
          value: 'name'
        },
        { text: 'Calories', value: 'calories' },
        { text: 'Fat (g)', value: 'fat' },
        { text: 'Carbs (g)', value: 'carbs' },
        { text: 'Protein (g)', value: 'protein' },
        { text: 'Sodium (mg)', value: 'sodium' },
        { text: 'Calcium (%)', value: 'calcium' },
        { text: 'Iron (%)', value: 'iron' }
      ],
      items: [
        {
            value: false,
            name: 'Frozen Yogurt',
            calories: 159,
            fat: 6.0,
            carbs: 24,
            protein: 4.0,
            sodium: 87,
            calcium: '14%',
            iron: '1%'
          },
          {
            value: false,
            name: 'Ice cream sandwich',
            calories: 237,
            fat: 9.0,
            carbs: 37,
            protein: 4.3,
            sodium: 129,
            calcium: '8%',
            iron: '1%'
          },
          {
            value: false,
            name: 'Eclair',
            calories: 262,
            fat: 16.0,
            carbs: 23,
            protein: 6.0,
            sodium: 337,
            calcium: '6%',
            iron: '7%'
          },
          {
            value: false,
            name: 'Cupcake',
            calories: 305,
            fat: 3.7,
            carbs: 67,
            protein: 4.3,
            sodium: 413,
            calcium: '3%',
            iron: '8%'
          },
          {
            value: false,
            name: 'Gingerbread',
            calories: 356,
            fat: 16.0,
            carbs: 49,
            protein: 3.9,
            sodium: 327,
            calcium: '7%',
            iron: '16%'
          },
          {
            value: false,
            name: 'Jelly bean',
            calories: 375,
            fat: 0.0,
            carbs: 94,
            protein: 0.0,
            sodium: 50,
            calcium: '0%',
            iron: '0%'
          },
          {
            value: false,
            name: 'Lollipop',
            calories: 392,
            fat: 0.2,
            carbs: 98,
            protein: 0,
            sodium: 38,
            calcium: '0%',
            iron: '2%'
          },
          {
            value: false,
            name: 'Honeycomb',
            calories: 408,
            fat: 3.2,
            carbs: 87,
            protein: 6.5,
            sodium: 562,
            calcium: '0%',
            iron: '45%'
          },
          {
            value: false,
            name: 'Donut',
            calories: 452,
            fat: 25.0,
            carbs: 51,
            protein: 4.9,
            sodium: 326,
            calcium: '2%',
            iron: '22%'
          },
          {
            value: false,
            name: 'KitKat',
            calories: 518,
            fat: 26.0,
            carbs: 65,
            protein: 7,
            sodium: 54,
            calcium: '12%',
            iron: '6%'
          }
      ],
    }
  },
  computed: {
    pages () {
      return this.pagination.rowsPerPage ? Math.ceil(this.items.length / this.pagination.rowsPerPage) : 0
    }
  },
  methods: {
  }
})
Torp answered 28/1, 2020 at 9:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.