Vuetify data table - manually display expandable rows - vue.js

I have a bunch of dynamic columns in a v-data table which I need to loop through and interrogate in order to display the correct info. It looks a bit like this (taken from the answer here: Vuetify format cell based on item type)
<v-data-table :item="items" ... >
<template v-for="header in headers" v-slot:[`item.${header.value}`]="{ item } ">
<template v-if="header.type === 'foo'">
<span style="color: red;">{{ item[header.value] }}</span>
</template>
<template v-else-if="header.value === 'data-table-expand'">
???
</template>
<template v-else>
{{ item[header.value] }}
</template>
</template>
</v-data-table>
Since I need the v-if statement, all other types default to the v-else. However, the v-else is not suitable for when a type is an expandable row. It will display a blank value for that column. So I created a v-else-if template to be able to capture the expandable row column and correctly render it to the screen.
The problem is that I don't know what to put in the template to indicate it's a column with expandable rows (https://vuetifyjs.com/en/components/data-tables/#expandable-rows). In other words it does not render the carat icon that shrinks/expands the subtable, nor does it render the clickable actions. How would I modify the v-else-if template to correctly render its contents?

I came up with a workaround using computed properties.
Instead of using
v-for="header in headers"
I changed it to a computed headers which is filtered.
<template v-for="header in headersIWant" v-slot:[`item.${header.value}`]="{ item } ">
<span style="color: red;">{{ item[header.value] }}</span>
</template>
...
computed: {
headersIWant() {
return this.headers.filter(x => x.type === 'foo');
}
}

Related

vuetify data table passing an item from parent to child to colour a field

Learning Vuetify and Vuetify (Loving both) but come across an issue I can't figure out so would appreciate someone sharing best practice please
I have created a component that contains a vuetify datatable and I pass the titles and items via props from a parent to the child, so far so good
The bit I can't figure out is that I want to loop through a specific field (the example I am using is item.calories as per the docs) and run a function over it.
I assume I pass the item.calories field as a prop but how do I then send that to a function
in my parent I pass to my DataTable component as follows
<DataTable
:headers="headers"
:content="content"
title="This is my data table title"
:myCalories="content.calories" <-- This bit is causing me the issue
/>
How in my DataTable component can I change the below to use the :myCalories prop, or is there a better approach I could consider?
<template v-slot:[`item.calories`]="{ item }">
<v-chip
:color="getColor(item.calories)"
dark
>
{{ item.calories }}
</v-chip>
</template>
My function
methods: {
getColor (calories) {
if (calories > 400) return 'red'
else if (calories > 200) return 'orange'
else return 'green'
},
},
I did wonder if I should run the function in the parent first and pass the result over but if you could advise on the best practice way to achieve the above it would be very much appreciated
Gibbo
I'm not sure it this will help but I had a similar problem and ended up using the body slot of the v-data-table and redefined my whole table.
This workaround could help you but this is certainly not the best approach to do it
<template v-slot:body="{ items, headers }">
<tbody>
<tr v-for="item in items" :key="item.name">
<td v-for="column in headers" :key="column.value">
<div v-if="column.value === 'calories'" :style="getColor(item.calories)">
{{ item[column.value] }}
</div>
<div v-else>
{{ item[column.value] }}
</div>
</td>
</tr>
</tbody>
</template>
Here is the codepen example https://codepen.io/taghurei-the-reactor/pen/YzaBNxw?editors=1111

How can I pass a v-data-table row information to child element

I have creating a list of users want to add them tags. I am using a data-table to display them and a combo box using chips to add or remove tags. How can I pass the user information to the method called when I add / remove a tag? Here is my code:
<v-data-table :headers="headers" :items="usersInfos" :search="search" :items-per-page="-1">
<template v-slot:[`item.tags`]="{ item }">
<v-combobox v-model="item.tags" :items="roles" chips clearable label="Rôles" multiple>
<template v-slot:selection="{ attrs, item, select, selected }">
<v-chip
v-bind="attrs"
:input-value="selected"
close
#click="select"
#click:close="removeRole(item)"
>
{{ item }} <!-- the tag -->
</v-chip>
</template>
</v-combobox>
</template>
</v-data-table>
Don't know if I understood it correctly but you can do following pass your item with your click event to your methods - call the function and use the passed parameter there.
in your template
#click=getSelectedItem(usersInfos)
in your script
methods: {
getSelectedItem(usersInfos) {
//do code here
console.log(usersInfos)
}
}
and than you have to use this where you have written your child element:
<child :usersInfo="usersInfo">
and in your child.vue you have to set props in your script like this:
props: ["usersInfo"]

Vuetify v-data-table render multiple v-edit-dialog

The docs has example for adding inline edit dialog to a column. I'm trying to add it to each column.
Copy & Paste of course.
Rendering row - But it will remove default function (i.e: sortable) of v-data-table row --> I don't choose
Using v-for with v-slot - But has error demo
<template v-for="header in headers" v-slot:item[header.value]="propsAPI">
<v-edit-dialog
:return-value.sync="propsAPI.item[header.value]"
#save="save"
#cancel="cancel"
#open="open"
#close="close"
:key="header.value"
>
{{ propsAPI.item[header.value] }}
<template v-slot:input>
<v-text-field
v-model="propsAPI.item[header.value]"
:rules="[max25chars]"
label="Edit"
single-line
counter
/>
</template>
</v-edit-dialog>
</template>
Any suggestion
You can replace
<template v-for="header in headers" v-slot:item[header.value]="propsAPI">
with
<template v-for="header in headers" v-slot:[`item.${header.value}`]="propsAPI">
This should redefine slot for each column.

Allow duplicated tags in bootstrap vue

I am in trouble with using duplicated tags in bootstrap Vue.
I am using the form tags in bootstrap Vue.
I cannot add the same value inside existing values.
['apple', 'orange', 'banana']
For example, I cannot add a new value of "apple" if the value of "apple" is already in the value array. This is because the form tag checks duplicated values and blocks to add them to the value array.
How can I add the same value to this array?
Here is the code I'm using:
<template>
<div>
<b-form-tags v-model="value" no-outer-focus class="mb-2">
<template v-slot="{ tags, inputAttrs, inputHandlers, tagVariant, addTag, removeTag }">
<b-input-group class="mb-2">
<b-form-input
v-bind="inputAttrs"
v-on="inputHandlers"
placeholder="New tag - Press enter to add"
class="form-control"
></b-form-input>
<b-input-group-append>
<b-button #click="addTag()" variant="primary">Add</b-button>
</b-input-group-append>
</b-input-group>
<div class="d-inline-block" style="font-size: 1.5rem;">
<b-form-tag
v-for="tag in tags"
#remove="removeTag(tag)"
:key="tag"
:title="tag"
:variant="tagVariant"
class="mr-1"
>{{ tag }}</b-form-tag>
</div>
</template>
</b-form-tags>
</div>
</template>
<script>
export default {
data() {
return {
value: ['apple', 'orange', 'banana']
}
}
}
</script>
This is because you are looping over a string array and using array elements as key. Please read this:
To give Vue a hint so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique key attribute for each item
Notice "you need to provide a unique key attribute for each item", but you are doing opposite and using array element as key, to handle this case you can always use the index from the loop, because index is unique for each element so:
<b-form-tag
v-for="(tag, index) in tags"
#remove="removeTag(tag)"
:key="index"
:title="tag"
:variant="tagVariant"
class="mr-1"
>{{ tag }}</b-form-tag>
</div>
Now this will not give you duplicate items error :)

Using generic value in v-slot:head

I try to create a generic Bootstrap Vue Table Component. For the field label in HTML format, I try to do something such:
<template v-for="field in fields" v-slot:head(field_name)>
<span v-translate render-html="true" v-html="field.label"></span>
</template>
Here, my problem is, when I put v-slot:head(field_name), the field_name is not generic and it is accepting as a string. So when I write field.key to v-slot:head, I want it to check the value of field.key but not field.key as the value itself.
<template v-for="field in fields" v-slot:head(field.key)>
<span v-translate render-html="true" v-html="field.label"></span>
</template>
Is there any way to handle this?
The syntax for dynamic slots is:
<template v-slot:[dynamicSlotName]>
// ...
</template>
Applied to your case:
<template v-for="field in fields" v-slot:[`head(${field.key})`]>
<span v-translate render-html="true" v-html="field.label"></span>
</template>