Close an expanded row in a Vuetify v-data-table through code - vuetify.js

I have a v-data-table that expands to show additional information and am trying to find a way, through code, to close the row before the user refreshes the data. Is there some event I can emit up to get any open rows to close?

You can use expanded.sync to retrieve all the expanded rows in a data table and to close all the rows that have been expanded, just reset the synched variable to an empty array.
<v-data-table
:headers="headers"
:items="desserts"
:expanded.sync="expanded"
item-key="name"
show-expand
class="elevation-1"
>
</v-data-table>
data(){
return {
...
expanded: []
}
}
methods: {
...
closeAll(){
this.expanded = []
}
}

It doesn't look like the expanded prop existed back in 1.5. If anyone else is looking for that, this seems to work: this.$refs.dataTable._data.expanded = {}; where you have ref="dataTable" on your v-data-table.
That expanded field is an object e.g. { "yourExpandedRowItemId": true } so resetting it collapses any open rows.

<v-data-table
:headers="headers"
:items="items"
:expanded.sync="expanded"
item-key="name.last"
group-by="country"
>
<template v-slot:group.header="{ group, headers, toggle, isOpen }">
<td :colspan="headers.length">
<v-btn #click="toggle" small icon :ref="group" :data-open="isOpen">
<v-icon v-if="isOpen">mdi-chevron-up</v-icon>
<v-icon v-else>mdi-chevron-down</v-icon>
</v-btn>
{{ group }}
</td>
</template></v-data-table>
closeAll () {
Object.keys(this.$refs).forEach(k => {
console.log(this.$refs[k])
if (this.$refs[k] && this.$refs[k].$attrs['data-open']) {
this.$refs[k].$el.click()
}
})
},
this is perfectly working for a close all expand by a "separate button outside a table " #vue2

Related

Vuetify Menu in header slot of data-table

I'm trying to put a <v-menu> within the header slot of a <v-data-table>.
This menu would then show filter options (v-autocomplete) for that column.
When the menu is clicked, I can't click the autocomplete to show its items, because then the menu closes.
Is this not possible in Vuetify?
I've tried passing :close-on-click="false" and :close-on-content-click="false"
For example (CodePen):
<v-data-table :items="desserts" :headers="headers">
<template #[`header.calories`]>
<v-menu top>
<template v-slot:activator="{ on, attrs }">
<v-btn icon v-bind="attrs" v-on="on"><v-icon>filter</v-icon></v-btn>
</template>
<v-autocomplete class="black" :items="headers" />
</v-menu>
</template>
</v-data-table>
You can use Event.stopPropagation(), it will prevents further propagation of the current event
Eg:
<v-autocomplete #click="clickOnAutocomplete" class="black" :items="headers" />
...
methods: {
clickOnAutocomplete(e) {
e.stopPropagation();
},
}
....

How to control expandable v-data-table expand icon's position?

From vuetify'e example, the icon shows up at right side of each row.
But when I making my own, the arrow showed up at the left side, I havent figured out how to control its position.
My code is like following
<v-data-table
:headers="headers"
:items="inputs"
item-key="id"
disable-pagination
dense
show-expand
single-expand
hide-default-footer
>
<template v-slot:[`item.value`]="{ item }">
<v-progress-linear
height="22"
></v-progress-linear
>
</template>
<template v-slot:expanded-item="{headers, item}">
<td :colspan="headers.length">
<InputDetails
:input="item"
/>
</td>
</template>
</v-data-table>
Added one more header into header list did the magic. { text: '', value: 'data-table-expand' },

Is it possible to sort Vuetify multiple selection on change?

I have a multiple selection Vue component that feeds items to display in an input box. As of now, it adds items based on the order of selection, but I wanted to template it to sort by sort_order after selection (objective_id, category_id, objective_code, objective_description, disabled_flag, sort_order are all passed into objectiveArray object). Is this possible to do in Vuetify?
<v-flex xs12>
<v-tooltip :disabled="!showTooltip" top>
<v-select
slot="activator"
class="objective-select"
v-model="record.objectives"
:items="objectiveArray"
label="Objective(s)"
placeholder="Enter Objective(s)"
:error-messages="objectiveErrors"
:return-object="true"
item-text="objectiveDescription"
multiple
#blur="v.$each[index].objectives.$touch()">
<template v-slot:selection="{ item, index }">
<v-chip
color="primary"
dark
class="objective-chip"
:class="{
mobile:isMobile,
tablet:isTablet
}">
<span>{{ item.objectiveDescription }}</span>
</v-chip>
</template>
</v-select>
<span>Select one or more procedure objective(s)</span>
</v-tooltip>
</v-flex>
You can sort your bound v-model after the #input event fires. Here is a simple example:
<template>
<div>
<v-select
v-model="selected"
:items="items"
item-text="id"
item-value="id"
multiple
#input="sortSelection"
return-object
>
</v-select>
</div>
</template>
<script>
export default {
data: () => ({
selected: [],
items: [{id:1},{id:2},{id:3},{id:4},{id:5},{id:6}]
}),
methods: {
sortSelection() {
this.selected.sort((x, y) => {
if (x.id > y.id) return 1
else if (y.id > x.id) return -1
else return 0
})
}
}
}
</script>
As long as your sort_order is a number you can just substitute it for the id field in my example.

Overwrite template slot dynamically

Fetching some headers config from a belongsTo() relation from Laravel. The responses looks like this:
My Vuetify data table config is this one:
<v-data-table
:headers="newHeaders"
:items="products"
item-key="name"
>
<template v-slot:header.stocks.0.pivot.quantity="{ header }">
{{ header.text }}
<v-icon>
mdi-pencil-outline
</v-icon>
</template>
</v-data-table>
I just want to use the slot to add my icon 'dynamically' to all 'Stock' headers adding (Could be 1, 2 3 or more headers).
How can I achieve this feature? I mean, right now is statically because if another stock is added I have to use <template v-slot:header.stocks.1.pivot.quantity="{ header }"> to do it.
Edited:
This is how the table looks like:
I use a solution from this answer: Same slot content for multiple template slots It was a kind of gorgeous and this is my solution:
Template tag
<v-data-table
:headers="newHeaders"
:items="products"
item-key="name"
>
<template
:slot="slotName"
slot-scope="props"
v-for="slotName in pivotNames">
{{ props.header.text }}
<v-icon>
mdi-pencil-outline
</v-icon>
</template>
Script tag
export default {
name: "Product",
data() {
return {
newHeaders: [...],
products: [...],
stockHeaders: [], //Have stock headers info
pivotNames: [] //Used in the v-for
}
},
methods: {
getPivotHeaders() {
const self = this;
this.stockHeaders.forEach(function(stock, index) {
let indexFound = stock["value"].includes("pivot.quantity");
if (indexFound) {
self.pivotNames.push("header." + stock["value"]); //Create name for slot template
}
});
}
}

Vuetify button icon with inline text

what I would like to achieve is a v-chip that act as a button and not like something to select...
So far I tried:
<v-btn icon>
<v-avatar>
<img :src="user.avatar" />
</v-avatar>
My Text
</v-btn>
But it is not looking as expected...
I also tried to wrap everything inside a chip but even here I can not manage to let it work properly...
Can someone explain how can I do it? Basically in my top toolbar I need to display the user icon with its name on the right, it should be inline with other v-btn icon elements and also, by clicking on the chip/btn it should open a dropdown...
Of course I don't need all this from you, just to understand how to create a icon button with some inline text on the right...
Thanks
I used v-chip to create a icon with text inline and used css to change the pointer of v-chip, wrapped with v-hover to maintain the elevation on hover and lastly wrapped v-hover by v-menu to show dropdown menu list when v-chip is clicked.
<div id="app">
<v-menu offset-y>
<template v-slot:activator="{ on }">
<v-hover>
<v-chip slot-scope="{ hover }"
:class="`elevation-${hover ? 5 : 2}`" v-ripple color="indigo" text-color="white" v-on="on">
<v-avatar>
<v-icon>account_circle</v-icon>
</v-avatar>
Sagar
</v-chip>
</v-hover>
</template>
<v-list>
<v-list-tile
v-for="(item, i) in items"
:key="i"
#click=""
>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
items: [
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me' },
{ title: 'Click Me 2' }
],
}
}
})
</script>
<style>
.v-chip .v-chip__content{
cursor: pointer;
}
</style>

Resources