Vuetify - How to access element in v-data-table at current cursor position - vuetify.js

I'm using v-data-table to list locations that are also shown on a map.
It would be nice to synchronize the highlighting so that if the cursor hovers over a
location in the table, the same location would be highlighted on the map.
Is there a way to access the element in v-data-table where the cursor is currently hovering over?

As one of the possible solutions you can override #items slot and include native mouseover event into <tr> tag:
<span class="text-h6">{{ `Last hovered location: ${hoveredLocation}` }}</span>
<v-data-table
:headers="headers"
:items="locations"
:items-per-page="5"
>
<template #item="{ item }">
<tr #mouseover="onMouseOver(item)">
<td>{{ item.city }}</td>
<td>{{ item.country }}</td>
</tr>
</template>
</v-data-table>
...
data () {
return {
hoveredLocation: null,
headers: [
{ text: 'City', value: 'city' },
{ text: 'Country', value: 'country' },
],
locations: [
{ id: 3, city: 'Paris', country: 'France'},
...
],
}
},
methods: {
onMouseOver(item) {
this.hoveredLocation = `${item.city} (${item.country})`;
}
}
Possibly you need to combine several events like mouseover/out, mouseenter/leave, etc.
Test this at CodePen.

Related

The checkboxes in the vue js loop do not work correctly

When using v-for, I need to allocate a number of materials with a checkbox. But when you click on the checkbox, a group of materials is immediately highlighted. This is due to the fact that the Quantity parameter is the same for many materials. How do I make sure that when I click on the checkbox, only one material is highlighted and the Quantity value is added to checkedMaterials?
<table>
<thead>
<tr>
<th>#</th>
<th>Material name</th>
<th>Количество</th>
</tr>
</thead>
<tbody>
<tr v-for="material in materials">
<td><input type="checkbox" :value="material" v-model="checkedMaterials">
{{material.id}}
</td>{{ material.name }}</td>
<td>{{ material.Quantity }}</td>
</tr>
export default {
name: "Show",
data() {
return {
materials: '',
checkedMaterials: [],
}
},
mounted() {
this.getPart()
this.getMaterials()
},
methods: {
getPart() {
axios.get(`/api/part/${this.$route.params.id}`).then(res => {
this.part = res.data.data
})
},
getMaterials() {
axios.get('/api/material').then(res => {
this.materials = res.data.data;
})
},
},
}
take id as value instead of whole material.
<tr v-for="material in materials">
<td><input type="checkbox" :value="material.id" v-model="checkedMaterials">
{{material.id}}
</td>{{ material.name }}</td>
<td>{{ material.Quantity }}</td>
</tr>
make computed propery for getting quantity .
computed : {
allSelectedMaterial() {
return this.materials.filter((material) =>
this.checkedMaterials.includes(material.id) )
},
selectedMaterialQuantitry(){
return this.allSelectedMaterial.map((material) => material.quantity)
},
uniqueSelectedQuantity(){
return [...new Set(this.selectedMaterialQuantitry)]
}
},
code : https://jsfiddle.net/d9nwz4kt/35/

Vuetify groupable table, is there a way to edit the the group name format?

The Vuetify table has an group-by prop, but instead of showing the header text it shows header value and then the group. Is there possible to change that?
What I'm looking for is like in the screenshot below, you can see the groups are like 'category: Candy'. The 'category' here is the header value. Is there a way to change it to 'Category' which would be the text?
{ text: 'Category', value: 'category', align: 'right' },
I could not find an appropriate attribute for you to set, but what could be used is a predefined object in the group.header slot:
<v-data-table :headers="headers" :items="desserts" item-key="name" sort-by="name" group-by="category" class="elevation-1" show-group-by>
<template v-slot:group.header="{groupBy, group, isOpen, toggle, remove}">
<td :colspan="headers.length">
<v-icon #click="toggle">
{{ isOpen ? 'mdi-minus' : 'mdi-plus' }}
</v-icon>
<span>{{customGroupNames[groupBy[0]]}} : {{group}}</span>
<v-icon #click="remove">
mdi-close
</v-icon>
</td>
</template>
</v-data-table>
Then you have to set the customGroupNames variable in your component:
data() {
return {
customGroupNames: { "category": "Cat", "dairy": "Dairy" },
headers: [...],
dessserts: [...]
}
}
You would essentially have to rebuild the group header row, but you will be able to display whatever you like.

How to alter a value in a v-data-table

I am new to vuetify and I'm trying to take the value in a column of a v-data-table and convert it to it's text equivalent, but can't find out how to do it.
headers: [
{ text: 'Name', value: 'name' },
{ text: 'Type', value: 'typeName(type)' },
]
I have tried typeName as a computed value and as a method:
typeName(typId) {
return ...
},
How do I get this to work?
Yes, you can format the column value by adding a explict function
Here is the working codepen which reverse the value of first column: https://codepen.io/chansv/pen/GRRjaqj?editors=1010
If you have headers type, no need to call the function from here,
instead we need to call from column by adding a template
headers: [
{ text: 'Name', value: 'name' },
{ text: 'Type', value: 'type' },
]
In the HTML , add a template with slot points to body
<v-data-table
:headers="headers"
:items="items" >
<template v-slot:body="{items}">
<tbody>
<tr v-for="item in items" :key="item.name">
<td>{{item.name}}</td>
<td>{{typeName(item.type)}}</td>
</tr>
</tbody>
</template>
</v-data-table>
Inside data property add a property typeName
data() {
return {
typeName: (type) => type.substring(2),
}
}

Laravel + Vuetify error: Error in render: this.items.slice is not a function" & Invalid prop: Expected Array, got Object

I'm using vuetify and laravel to display some data from an array using vuetify's data table. The data get's displayed on the table fine, but these two errors appear? I need some help as for what I can do to avoid these errors.
Errors:
Error in render: "TypeError: this.items.slice is not a function"
Invalid prop: type check failed for prop "items". Expected Array, got Object
I've tried searching for the Invalid prop error for a while now but still nothing helped. As for the error in render part, this is where I really haven't found anything.
.Vue Data table:
<v-data-table
:headers="headers"
:items="lists"
class="elevation-1"
>
<v-btn color="success">Success</v-btn>
<template v-slot:items="lists">
<td class="text-xs-left">{{ lists.item.Customer }}</td>
<td class="text-xs-right">{{ lists.item.Address }}</td>
<td class="justify-center layout px-0">
<v-icon small class="mr-2" color="teal">visibility</v-icon>
<v-icon small class="mr-2" color="orange darken-2">edit</v-icon>
<v-icon small color="red darken-2">delete</v-icon>
</td>
</template>
script:
<script>
let Add = require('./Add.vue');
export default {
components: { Add },
data () {
return {
lists:{},
errors:{},
headers: [
{
text: 'Customer',
align: 'left',
value: 'Customer'
},
{ text: 'Address', value: 'Address' },
{ text: 'Contact No', value: 'CustomerContactNo' },
],
}
},
mounted(){
axios.post('/getData')
.then((response)=> this.lists = response.data)
.catch((error) => this.errors = error.response.data)
}
}
</script>
How do I avoid these errors? Any help is appreciated, Thanks.
Both errors suggest you have a prop called items that is being passed an object instead of an array.
A candidate would be the prop called items here:
<v-data-table
:headers="headers"
:items="lists"
class="elevation-1"
>
Based on those errors we can guess that the value lists might incorrectly be an object. Digging further, if we take a look in your JS code we find this:
data () {
return {
lists: {},
So your initial value is an object, not an array. Once your remote data shows up it will be replaced with an array and everything will appear to work correctly.
Try changing lists: {}, to lists: [],.

How to use vuetify's custom sort?

I'd like to use custom-sort in my data table. My goal is to sort the table DESC as opposed to the default ASC. But I don't know-how.
This is the start of my data table component:
<v-data-table
:headers="headers"
:items="acts"
hide-actions
class="elevation-1"
>
<template slot="items" slot-scope="props">
<td>{{ props.item.id }}</td>
<td>{{ props.item.name }}</td>
<td class="text-xs-center">{{ props.item.provider.id }}</td>
<td class="text-xs-center">{{ props.item.category.name }}</td>
<td class="text-xs-center">{{ props.item.budget }}</td>
<td class="text-xs-center">{{ props.item.location.name }}</td>
<td class="text-xs-center">{{ props.item.deets }}</td>
<td class="text-xs-center">{{ props.item.keeping_it_100 }}</td>
<td class="text-xs-center"><img width="50" height="50" :src="props.item.inspiration.inspiration"></td>
<td class="justify-center layout px-0">....
And this is the script I'm using:
<script>
export default {
data () {
return {
dialog: false,
customerSort: {
isDescending: true,// I tried this? as the kabab format throws an error
},
headers: [
{ text: 'ID', value: 'id'},
{ text: 'Name', value: 'name' },
{ text: 'Provider', value: 'provider' },
{ text: 'Category', value: 'category' },
{ text: 'Budget', value: 'budget' },
{ text: 'Country', value: 'location', sortable: true },
{ text: 'Keeping it 100%', value: 'keeping_it_100', sortable: false },
{ text: 'deets', value: 'deets', sortable: false },
{ text: 'inspiration', value: 'inspiration', sortable: false },
{ text: 'Cover', value: 'cover', sortable: false },
{ text: 'Actions', value: 'actions', sortable: false }
],
According to docs it is a function prop. But I haven't found an example on how to pass it.
This is a screenshot of the function...
You can use a function like this-
customSort(items, index, isDesc) {
items.sort((a, b) => {
if (index === "date") {
if (!isDesc) {
return compare(a.date, b.date);
} else {
return compare(b.date, a.date);
}
}
});
return items;
}
Where the compare is a function which compares a.date and b.date and returns 1 or -1
isDesc is a variable passed by the table which tells in what order does the user want to sort it. If you want to sort in desc, just use !isDesc in the if-else condition
To use this in your template just use
<v-data-table
:headers="headers"
:items="Data"
:custom-sort="customSort"
>
<template slot="items" slot-scope="props">
<td class="font-weight-black">{{ props.item.date }}</td>
<td class="text-xs-right">{{ props.item.time }}</td>
<td class="text-xs-right">{{ props.item.name }}</td>
</template>
</v-data-table>
To make sure your other fields still work with the normal sort use
customSort(items, index, isDesc) {
items.sort((a, b) => {
if (index === "date") {
if (!isDesc) {
return dateHelp.compare(a.date, b.date);
} else {
return dateHelp.compare(b.date, a.date);
}
} else {
if (!isDesc) {
return a[index] < b[index] ? -1 : 1;
} else {
return b[index] < a[index] ? -1 : 1;
}
}
});
return items;
}
Although it's an old question ...
For special sorting of only one column, you could use the property sort in the headers array.
See also https://vuetifyjs.com/en/api/v-data-table/#headers
Like so:
// in data ...
headers: [
...
{
text: "Date",
sortable: true,
value: "date",
sort: (a, b) => a.time_stamp - b.time_stamp
},
...
]
use it like
<v-data-table
:headers="headers"
...
>
Based on this answer code about custom-filter, I tried using custom-sort.
Please refer to this answer if you apply it to your code.
By the following code, I have confirmed sorting when I click 'Calories' header.
My CodePen
new Vue({
el: '#app',
data() {
return {
food: [
{ name: 'Bakchoi', type: 'vegetable', calories: 100 },
{ name: 'Pork', type: 'meat', calories: 200 },
{ name: 'Chicken Thigh', type: 'meat', calories: 300 },
{ name: 'Watermelon', type: 'fruit', calories: 10 },
],
headers: [
{ text: 'Name', align: 'left', value: 'name' },
{ text: 'Food Type', align: 'left', value: 'type' },
{ text: 'Calories', align: 'left', value: 'calories' },
],
search: '',
};
},
methods: {
customSort(items, index, isDescending) {
// The following is informations as far as I researched.
// items: 'food' items
// index: Enabled sort headers value. (black arrow status).
// isDescending: Whether enabled sort headers is desc
items.sort((a, b) => {
if (index === 'calories') {
if (isDescending) {
return b.calories - a.calories;
} else {
return a.calories - b.calories;
}
}
});
return items;
}
}
})
<script src="https://unpkg.com/vue#2.4.2/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#0.15.2/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#0.15.2/dist/vuetify.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons">
<div id="app">
<v-app>
<v-select
label="Food Type"
:items="['vegetable', 'meat', 'fruit']"
v-model="search"
></v-select>
<v-data-table
:headers="headers"
:items="food"
:search="search"
:custom-sort="customSort"
hide-actions
>
<template slot="items" scope="{ item }">
<td>{{ item.name }}</td>
<td>{{ item.type }}</td>
<td>{{ item.calories }}</td>
</template>
</v-data-table>
</v-app>
</div>
NOTE: the following answer is for Vuetify 1.5.x
A little late to the party here, if all you want to do is sort descending by a single field, then custom-sort it not what you want to use, you're better off using the :pagination.sync prop
Custom sort is used when you want to change the behaviour of the comparison function (e.g sorting based off the reverse or lowercase version of a string, or proper sorting of date strings in the format 'DD-MM-YYYY').
If you want to use the default descending functionality, use the :pagination.sync prop, like so:
<v-data-table
:headers="headers"
:items="acts"
:pagination.sync="pagination"
>
<template v-slot:items="props">...</template>
</v-data-table>
In your script, set pagination:
data () {
return {
pagination: {
sortBy: 'id', // The field that you're sorting by
descending: true
}
}
}
This specifies that you want the table to be initially sorted by descending id - id can be changed to any field name in the dataset.
It's worth noting that this only specifies the default behaviour, and if you have sorting enabled for your other headers, users can still sort the table by any field.
To Build on the response provided by bhaskar
I had to edit the last code sample to the following in order to work on vuetify 2.x. The code sorts the date columns by their epoch time which is stored under the time_stamp key. The code also allows the default sorting of numbers and strings (strings are sorted alphabetically)
customSort(items, index, isDesc) {
items.sort((a, b) => {
if (index[0] == "date") {
if (!isDesc[0]) {
return a.time_stamp - b.time_stamp;
} else {
return b.time_stamp - a.time_stamp;
}
} else if (!(isNaN(a[index[0]]))) {
if (!isDesc[0]) {
return (a[index[0]] - b[index[0]]);
} else {
return (b[index[0]] - a[index[0]]);
}
} else {
if (!isDesc[0]) {
return (a[index[0]] < b[index[0]]) ? -1 : 1;
} else {
return (b[index[0]] < a[index[0]]) ? -1 : 1;
}
}
});
return items;
}
In vuetify 2 just use sortBy="date" and update: sort-desc
<v-data-table
:headers="headers"
:items="acts"
:pagination.sync="pagination"
sortBy="date"
update: sort-desc
>

Resources