Reputation: 675
I have encountered a strange behaviour of the Tooltip component in Vuetify. I am using this component inside Vuetify's DataTable component, where I use a slot for one of the data columns into which I add Vuetify's Button component and then I use the Tooltip component inside that button.
Problem definition:
The tooltip behavior is following:
Additional information:
I have found out that the behavior is probably caused by the fact that in my app, I have set this component to be kept alive via
<keep-alive :include="['PrintHistory']">
<router-view />
</keep-alive>
When I remove the PrintHistory
string, it behaves as expected.
I have also found out that when I set the open-delay
parameter to a higher number, it shows the tooltip in the top left corner with higher delay.
It does not matter what page I'm redirecting to, the problem still prevales.
The code of the entire component:
<template>
<div>
<v-layout style="width:100%;" justify-space-between class="mb-0">
<h2>{{ $t('print_history.title') }}</h2>
</v-layout>
<v-card class="elevation-1 my-1 pt-1" v-resize="onResize">
<v-layout style="text-align: right;">
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
:label="$t('print_history.search')"
class="ma-2"
></v-text-field>
</v-layout>
<v-data-table :headers="headers"
:items="rows"
:loading="loading"
:loading-text="$t('v_big_table.loading')"
:sort-by="'action_at'"
:sort-desc="true"
:search="search"
:page.sync="page"
@page-count="page_count = $event"
hide-default-footer
:items-per-page="computed_items_per_page">
<template v-for="header in headers" v-slot:[`header.`+header.value]="{ header }">
<span class="table_header" v-bind:key="`header_customization_`+header.value">{{ $t(header.text) }}</span>
</template>
<template v-slot:item.show_file="{ item }">
<!-- The redirecting is not yet finished -->
<v-btn :to="`/pdfjs-viewer`" icon small class="ma-0" color="primary">
<v-tooltip top open-delay="600" :color="tooltip_bg_color">
<template v-slot:activator="{ on, attrs }">
<v-icon
v-bind="attrs"
v-on="on">mdi-file-search-outline</v-icon>
</template>
<span class="tooltip">{{ $t('print_history.show_file') }} {{ item['path_to_file'].split("/")[item['path_to_file'].split("/").length-1] }}</span>
</v-tooltip>
</v-btn>
</template>
</v-data-table>
<v-pagination
v-model="page"
:length="page_count"
:total-visible="9"
></v-pagination>
</v-card>
</div>
</template>
<script>
/**
* @typedef {Object} Sorter - stores information about column sorting
* @property {string} field - unique name of the column to sort
* @property {string} dir - direction of sorting: ascending ('asc'), descending ('desc')
*/
/**
* @typedef {Object} Filter - stores information about column sorting
* @property {string} field - unique name of the column to filter
* @property {string} operator - operator defining the filter
* @property {string} value - direction of sorting: ascending ('asc'), descending ('desc')
* @property {string} color - color of the v-chip when the filter is shown
*/
import { utcTimeStamp, utcToLocal } from '../../../utils'
/**
* Shows a history of printing arranged in a table with sorting and filtering capabilities.
*/
export default {
name: "PrintHistory",
data () {
return {
tooltip_bg_color: 'rgba(0,0,0,0.7)',
err_msg: '',
search: '',
row_count: 0,
total_row_count: 0,
rows: [],
rows_filtered: [],
loading: true,
page: 1,
page_count: null,
default_items_per_page: 13,
window_size: {
x: 0,
y: 0
},
initial_sorters: [{field: 'action_at', dir: 'desc'}],
headers: [
{
text: 'print_history.date_and_time',
value: 'action_at',
align: 'end'
},
{
text: 'print_history.report_type',
value: 'translated_report_type'
},
{
text: 'print_history.user_id',
value: 'user_id'
},
{
text: 'print_history.user_name',
value: 'user_name'
},
{
text: 'print_history.state',
value: 'translated_state'
},
{
text: 'print_history.show_file',
value: 'show_file',
sortable: false,
},
],
last_update: null,
}
},
computed: {
computed_items_per_page() {
return Math.max(Math.floor((this.window_size.y - 300)/48), 1)
}
},
methods: {
utcToLocal,
/**
* Loads data from database. Assigns loading error in case the data cannot be loaded.
*/
loadData() {
this.loading = true
this.last_update = utcTimeStamp()
let start_time = Date.now()
this.$store.dispatch('getPrintHistory')
.then((response) => {
this.rows = this.transformData(response.data)
this.row_count = this.rows.length
this.total_row_count = response.data.total_row_count
console.log("Total time:" + (Date.now() - start_time))
})
.catch(() => {
this.err_msg = 'errors.error_loading_data'
this.data = []
})
.finally(() => {
this.loading = false
})
},
/**
* This will show file in a javascript PDF browser once implemented.
* @param absolute_path absolute path to the file to be shown
*/
showFile(absolute_path) {
console.log(absolute_path)
},
/**
* Processes data before saving them to rows.
* @param {object[]} data_to_transform array of objects that should be processed
* @return {object[]} array of objects that are formatted for the data table
*/
transformData(data_to_transform) {
let data_to_return = data_to_transform
data_to_return.forEach((entry) => {
entry['user_name'] = entry.user.name
entry['path_to_file'] = entry.misc.path_to_file
entry['action_at'] = this.$d(utcToLocal(entry.action_at), 'datetime')
entry['translated_report_type'] = this.$t(`print_history.report_types.` + entry.report_type)
entry['translated_state'] = this.$t(`print_history.states.` + entry.state)
})
return data_to_return
},
onResize() {
this.window_size = {x: window.innerWidth, y: window.innerHeight}
}
},
beforeMount() {
this.loadData()
},
activated() {
// check if the server has new data, refresh component data if true
this.$store.dispatch('lastDataUpdate')
.then((response) => {
if (response.data > this.last_update) {
this.loadData()
}
})
// on error refresh anyway
.catch(() => {
this.loadData()
})
},
}
</script>
<style scoped>
.table_header {
font-weight: bold;
color: black;
}
</style>
An example of the response.data
retrieved from the database via the loadData
method:
[{
action_at: "2021-01-20T13:03:39.528843",
id: "1",
inventory_id: "1",
reporty_type: "my_report_type",
state: "archived",
misc: {
path_to_file: '/some/path/to/file.pdf'
},
user: {
name: "John Doe",
id: "123456",
roles: {role_1: true}
},
user_id: "123456"
},
{
action_at: "2021-01-20T13:05:39.528843",
id: "2",
inventory_id: "1",
reporty_type: "my_other_report_type",
state: "moved_to_print",
misc: {
path_to_file: '/some/path/to/file2.pdf'
},
user: {
name: "Jane Doe",
id: "123457",
roles: {role_1: true}
},
user_id: "123457"
}]
Question:
Is this tooltip behavior a bug or do I have to set some additional settings for it? Is there some workaround so it behaves correctly even when the component is kept alive?
In case of some additional information, ask away.
Upvotes: 2
Views: 3285
Reputation: 505
Seems like you have the same issue as this: https://github.com/vuetifyjs/vuetify/issues/2480 but with different versions of Vuetify.
There are many issues and requests for an attribute of tooltip for buttons, but for now the solution can be like in this fix: https://github.com/vuetifyjs/vuetify/pull/2780 :
show
in the data (I think it should be set to false if you use v-model for the tooltip)@click="show = false"
v-if="show"
or v-model="show"
Upvotes: 1