7
votes

App.vue

<template>
    <v-app id="inspire">
        <v-navigation-drawer
                v-model="drawer"
                app
        >
            <v-list dense>
                <v-list-item link>
                    <v-list-item-action>
                        <v-icon>mdi-home</v-icon>
                    </v-list-item-action>
                    <v-list-item-content>
                        <v-list-item-title>Home</v-list-item-title>
                    </v-list-item-content>
                </v-list-item>
                <v-list-item link>
                    <v-list-item-action>
                        <v-icon>mdi-contact-mail</v-icon>
                    </v-list-item-action>
                    <v-list-item-content>
                        <v-list-item-title>Contact</v-list-item-title>
                    </v-list-item-content>
                </v-list-item>
            </v-list>
        </v-navigation-drawer>

        <v-app-bar
                app
                color="indigo"
                dark
        >
            <v-app-bar-nav-icon @click.stop="drawer = !drawer"/>
            <v-toolbar-title>Application</v-toolbar-title>
        </v-app-bar>

        <v-content>
            <v-container fluid>
                <router-view></router-view>
            </v-container>
        </v-content>
        <v-footer
                color="indigo"
                app
        >
            <span class="white--text">&copy; 2019</span>
        </v-footer>
    </v-app>
</template>

Home.vue:

<template>
    <v-layout fluid>
        <template>
            <v-data-table
                    height="100%"
                    :headers="headers"
                    :items="desserts"
                    :items-per-page="10"
                    class="elevation-1"
                    style="margin: 0px; padding: 0px; width: 100%; height: 100%"
            ></v-data-table>
        </template>
    </v-layout>
</template>

<script>
    export default {
        data () {
            return {
                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: 'Iron (%)', value: 'iron' },
                ],
                desserts: [
                    {
                        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%',
                    },

                ],
            }
        },
    }
</script>

I try to set the height of the table (v-data-table or v-simple-table) so that it is flush at the top and bottom. The table has the correct width and is also correctly fixed at the top left. The problem is, if I have a lot of data, the table just keeps expanding downwards. Fixed headers are of no use because they simply disappear upwards. The table should always be as high as there is space between header and footer.

How can I set the height of the table so that it always fits between header and footer and does not expand downwards.

2
What do you want to happen ?Qonvex620
The table should not become larger. It should become scrollable. At the moment, the table is getting bigger and bigger and you have to scroll down the whole page. As a result, the table header also slides upwards. But it should be fixed. You could give the table a fixed height. For example 300 px. But the size must vary depending on the display. It should fit exactly between header and footer.SamuelTJackson
If you are using the latest Vuetify 2.x - there is a prop fixed-header which supposedly will help you but I have no clue whether you can fix the footer, too.IVO GELOV

2 Answers

11
votes

Update at Jan 7, 2021: Based on @Jack answer, I added trick 0. I guess, it should be more flexible than others.

Trick 0. You could create your own page template and combine it with v-resize directive.

Example page with Header, Title, Filter and Table blocks:

<template>
  <div v-resize="onResize">
    <slot name="header" />
    <slot name="toolbar" />
    <slot name="filter" />
    <div ref="resizableDiv">
      <slot name="table" :table-height="tableHeight" />
    </div>
  </div>
</template>

<script>
export default {
  name: "resizable-page",
  data() {
    return {
      tableHeight: 0,
    };
  },
  props: {
    footerHeight: {
      type: Number,
      default: 59, //default v-data-table footer height
    },
  },
  methods: {
    onResize() {
      this.tableHeight =
        window.innerHeight -
        this.$refs.resizableDiv.getBoundingClientRect().y -
        this.footerHeight;
    },
  },
};
</script>

There is a codesandbox with the example.


Old answer:

I recently encountered the same problem and haven't yet found a simple solution.

But there are 2 tricks that may be helpful to you.

Trick 1. Use v-data-table attribute height in vh. Example:

<v-data-table
  height="70vh"
  fixed-header
  :headers="headers"
  :items="desserts"
  :items-per-page="10"
  class="elevation-1"
  style="width: 100%"
></v-data-table>

Using this trick you can make the table shrink and grow in accordance with the height of the browser window.

Some advantages:

  1. Fairly simple solution - you should only precalculate vh value
  2. It looks ok in most cases

Some disadvantages:

  1. You should set a specific vh to every table on every page. This is not an universal solution.
  2. Starting from a certain browser window height you'll get 2 scroll bars in your browser - one in table and another one for the whole page. In order to avoid the appearance of the 2nd scroll bar as far as possible, you should specify the lowest possible vh value. So, on the large screens there will still be some space between table and footer.

Trick 2. Use v-resize directive and recalculate table's heigth.

Example for your template:

<v-layout fluid v-resize="onResize">
  <v-data-table
    :height="windowSize.y - 64 - 24 - 59 - 36"
    fixed-header
    :headers="headers"
    :items="desserts"
    :items-per-page="10"
    class="elevation-1"
    style="width: 100%"
  ></v-data-table>
</v-layout>
...
<script>
  export default {
    data () {
      return {
        ...
        windowSize: {
          x: 0,
          y: 0,
        },
      }
    },
    ...
    methods: {
      onResize () {
        this.windowSize = { x: window.innerWidth, y: window.innerHeight };
      },
    }
  };
</script>

Notes for constants in height prop: 64 is your header height, 24 - table padding (12 for top + 12 for bottom), 59 - table footer height, 36 - page footer height.

Some advantages:

  1. If you precalculate your height correctly, second scroll bar will never appear and your table will fit in your page between header and footer.

Some disadvantages:

  1. Not a universal solution
  2. You should calculate this height for every page. It will be much harder than in trick 1. Also don't forget that some elements (by example, table filters) may change their height according to some sizes (like xs, sm, md, ...)

Also take a look that in both cases I use fixed-header attribute. This attribute was firstly introduced in Vuetify 2.0 and (according to docs) does not work in IE11.

0
votes

Another solution is to wrap the v-data-table in a div and access it through the virtual DOM.

You can then apply any height calculation to your div and use its height on the v-data-table.

<v-layout fluid v-resize="updateDataTableHeight">
  <div ref="parentDiv">
    <v-data-table
      :height="dataTableHeight"
    /></v-data-table>
  </div>
</v-layout>
...
<script>
  export default {
    data () {
      return {
        ...
        dataTableHeight: 0,
      }
    },
    ...
    methods: {
      updateDataTableHeight () {
      this.dataTableHeight= this.$refs.parentDiv.clientHeight;
      },
    }
  };
</script>

It's not a perfect solution but it allows for much more flexibility, such as % and calc CSS stylings.