3

Good morning, I am modifying the slot header of a data table in vuetify.js to add a tooltip, all this does it well, but the arrows of asc and desc are not shown, I would like to know what I am doing wrong.

<template  v-slot:header="{ props: { headers } }">
    <thead>
        <tr>
            <th 
                style="white-space: nowrap"
                :class="['column sortable', pagination.descending ? 'desc' : 'asc', header.value === pagination.sortBy ? 'active' : '']"
                @click="changeSort(header.value)"
                v-for="element in headers" 
                :key="element.text">
                <v-tooltip top>
                    <template v-slot:activator="{ on }">
                        <span v-on="on">{{element.text}}</span>
                    </template>
                    <span>{{element.text}}</span>
                </v-tooltip>
            </th>
        </tr>
    </thead>
</template>
Almic
  • 77
  • 1
  • 7

1 Answers1

7

As noted in the documentation,

It is important to note some slot (eg: item/body/header) will completely takes over the internal rendering of the component which will require you to re-implement functionalities such as selection and expansion.

But you can customize the default header

You can use the dynamic slots header. to customize only certain columns. is the name of the value property in the corresponding header item sent to headers.

Modifying the codepen in that second section of the documentation, you can see how you can add tooltips for each header, using dynamic slot names. Here I have a tooltip for the first 3 columns, and just the default text for the remaining columns, but populating a tooltip text for all in headerTooltips will produce tooltips for all headers.

<div id="app">
  <v-app id="inspire">
    <v-data-table
      :headers="headers"
      :items="desserts"
      class="elevation-1"
    >
      <template v-for="header in headers" v-slot:[`header.${header.value}`]="{ header }">
        <v-tooltip v-if="headerTooltips[header.value]" bottom :key="header.value">
          <template v-slot:activator="{ on }">
            <span v-on="on">{{ header.text }}</span>
          </template>
          <span>{{ headerTooltips[header.value] }}</span>
        </v-tooltip>
        <span v-else>{{ header.text }}<span>
      </template>
    </v-data-table>
  </v-app>
</div>
new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: () => ({
    headers: [
      {
        text: 'Dessert (100g serving)',
        align: 'start',
        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' },
    ],
    headerTooltips: {
      name: 'Name tooltip',
      calories: 'Calories tooltip',
      fat: 'Fat tooltip'
    },
    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%',
      },
      {
        name: 'Eclair',
        calories: 262,
        fat: 16.0,
        carbs: 23,
        protein: 6.0,
        iron: '7%',
      },
      {
        name: 'Cupcake',
        calories: 305,
        fat: 3.7,
        carbs: 67,
        protein: 4.3,
        iron: '8%',
      },
      {
        name: 'Gingerbread',
        calories: 356,
        fat: 16.0,
        carbs: 49,
        protein: 3.9,
        iron: '16%',
      },
      {
        name: 'Jelly bean',
        calories: 375,
        fat: 0.0,
        carbs: 94,
        protein: 0.0,
        iron: '0%',
      },
      {
        name: 'Lollipop',
        calories: 392,
        fat: 0.2,
        carbs: 98,
        protein: 0,
        iron: '2%',
      },
      {
        name: 'Honeycomb',
        calories: 408,
        fat: 3.2,
        carbs: 87,
        protein: 6.5,
        iron: '45%',
      },
      {
        name: 'Donut',
        calories: 452,
        fat: 25.0,
        carbs: 51,
        protein: 4.9,
        iron: '22%',
      },
      {
        name: 'KitKat',
        calories: 518,
        fat: 26.0,
        carbs: 65,
        protein: 7,
        iron: '6%',
      },
    ],
  }),
})

Here is that Codepen: https://codepen.io/keeganwitt/pen/ExVVyqa

tony19
  • 125,647
  • 18
  • 229
  • 307
Keegan
  • 11,345
  • 1
  • 25
  • 38
  • This is great! However, when I try and add to example here: https://vuetifyjs.com/en/components/data-tables/#crud-actions it raise exception "Unexpected identifier" and I think it refers to the v-slot header syntax. A reference link to how to interpret syntax `[\`header.${header.value}\`]` in `v-slot:[\`header.${header.value}\`]="{ header }"`would be helpful. Thanks! – Adam Cox Nov 15 '20 at 18:31
  • BTW... I am using inside template: \`....\` so I think I need to escape the backticks or implement alternative? – Adam Cox Nov 15 '20 at 18:37
  • 1
    What I came up with is escaping the backticks AND the `$` - this ` – Adam Cox Nov 15 '20 at 19:02
  • Are you using some kind of template preprocessor? I don't see this issue. Do note that the dynamic slot names requires Vue 2.6. There are some character restrictions, but in the example I have above, I'm not using any of those characters. See https://vuejs.org/v2/guide/syntax.html#Dynamic-Argument-Value-Constraints. – Keegan Nov 18 '20 at 02:44
  • I am using this within the context of SAP XSA. What I know is that without escaping the backticks and the `$` found inside of the backticks used to declare the template within the vue component, they are incorrectly interpreted rendering the logic invalid. – Adam Cox Nov 18 '20 at 04:23
  • Sorry, I don't know anything about that. I'd need to know more about how it's being packaged for that environment. If it works I guess /shrugs – Keegan Nov 19 '20 at 01:38
  • I am using vue component and assigning the template to property of the component using backticks. Would be interested to learn if there is another way to factor the work so that I can use a separate HTML file. Angular allows, but I can't see same in vue. Cheers! – Adam Cox Nov 20 '20 at 01:38