expanded-item not triggering events - vuetify.js

I'm currently having the problem that when the checkboxes in the expanded-item slot are clicked, these do not change their value.
I have also tried using the directive #click, but this also didn't trigger the checkbox to change its value.
<template>
<v-data-table
:headers="headers"
:items="items"
show-expand
single-expand
>
<template v-slot:expanded-item="{ item, headers }">
<td :colspan="headers.length">
<v-row v-for="(cs, index) in item.c" :key="index">
<v-simple-checkbox
v-model="cs.selected"
:ripple="false"
>
</v-simple-checkbox>
</v-row>
</td>
</template>
</v-data-table>
</template>
<script>
export default {
data() {
return {
headers: [
{
text: 'A',
align: 'center',
sortable: false,
value: 'a'
},
{
text: 'B',
align: 'center',
sortable: false,
value: 'b'
}
],
items: [
{ a: 'my A', b: 'my B', c: [false, false] },
{ a: 'my A', b: 'my B', c: [false, false] }
]
}
}
}
</script>
Link to reproduction: https://codesandbox.io/s/vuetify-playground-forked-1omj9p?file=/src/layout.vue

If I understand correctly, you want to select the checkboxes of expanded panel after clicking them. Please see if this is what you are looking for. You also need to give a unique field for each row in items so that selecting checkboxes works ( I have added id field here). Once we click the button, selected checkboxes id can be captured (check console.log).
Link https://codesandbox.io/s/vuetify-playground-forked-6u5wry
<template>
<v-app>
<v-main>
<v-data-table
:headers="headers"
:items="items"
show-expand
single-expand
>
<template v-slot:expanded-item="{ item, headers }">
<td :colspan="headers.length">
<v-data-table
:headers="headers"
:items="items"
class="elevation-1"
v-model="selected"
show-select
item-key="id"
:hide-default-header="true"
:hide-default-footer="true"
:footer-props="{ itemsPerPageOptions: [-1] }"
>
</v-data-table>
</td>
</template>
</v-data-table>
<v-btn
small
color="blue darken-4"
rounded
dark
#click.prevent="selectcheckbox"
>Check Selected</v-btn
>
</v-main>
</v-app>
</template>
<script>
export default {
components: {
//MyDialog: () => import('./features/dialog.vue'),
//MyTabs: () => import('./features/tabs'),
//DatePicker: () => import('./features/date-picker.vue')
},
data() {
return {
selected: [],
headers: [
{
text: 'A',
align: 'center',
sortable: false,
value: 'a'
},
{
text: 'B',
align: 'center',
sortable: false,
value: 'b'
}
],
items: [
{ id: 1, a: 'my A', b: 'my B', c: [false, false] },
{ id: 2, a: 'my A', b: 'my B', c: [false, false] }
]
}
},
methods: {
selectcheckbox() {
console.log('selected checkboxes', this.selected)
}
}
}
</script>
<style>
.b1,
[b1] {
border: 1px dashed red;
}
.h-100 {
height: 100%;
}
.w-100 {
width: 100%;
}
::-webkit-scrollbar {
display: none;
}
.v-btn,
.v-tabs__item {
text-transform: none !important;
}
</style>

Related

Vuetify v-combobox validations not working

I have a Vuetify(v. 1.9.0) v-combobox with validation that at least one item should be selected from the menu. For some reason the validation is not triggered and there are no errors in the console.
<v-combobox
multiple
item-text="name"
item-value="id"
:items="items"
:rules="[rules.required]"
></v-combobox>
<script>
export default {
data: () => ({
rules: {
required: value =>
!!value || "Required."
}
})
}
</script>
What am I missing?
Try this example:
<template>
<v-app>
<v-content>
<v-form ref="form">
<div>
<v-combobox
multiple
item-text="name"
item-value="id"
:items="items"
:rules="[required]"
v-model="selected"
/>
selected = {{ selected }}
</div>
<div>
<v-btn #click="$refs.form.validate()">Validate</v-btn>
</div>
</v-form>
</v-content>
</v-app>
</template>
<script>
export default {
name: 'app',
data: () => ({
selected: null,
items: [
{ id: 1, name: 'Option 1' },
{ id: 2, name: 'Option 2' },
{ id: 3, name: 'Option 3' },
],
}),
methods: {
required(value) {
if (value instanceof Array && value.length == 0) {
return 'Required.';
}
return !!value || 'Required.';
},
},
};
</script>

Implement vue draggable in a table. Laravel

I'm trying to create a survey with the option to order the questions that are displayed in a table when creating the survey.
I'm using vue draggable and the example works but I don't know how to use this with a table and still get the rows to be draggable
Example
<draggable v-model="section" #start="drag=true" #end="drag=false">
<div v-for="section in surveySections" :key="section.id">{{section.title}}</div
</draggable>
This is the table
<el-table
:data="form.question_id"
border>
<draggable v-model="surveyQuestions" #start="drag=true" #end="drag=false">
<el-table-column prop="title" label="Pregunta"></el-table-column>
<el-col :xs="5">
<el-table-column fixed="right" label="Operaciones">
<template slot-scope="scope">
<el-button
#click.native.prevent="deleteRow(scope.$index, form.question_id)"
type="text" size="small">
<span class="icon-create">Eliminar</span>
<i class="el-icon-delete-solid"></i>
</el-button>
</template>
</el-table-column>
</el-col>
</draggable>
</el-table>
How can I get this to work?
I must have 50 reputation to comment!
SO.
you can see elementUI Table组件实现拖拽效果
e.g
npm install sortablejs --save
// Element table must specify row-key . Otherwise, the order will be wrong
import Sortable from 'sortablejs'
<template>
<div style="width:800px">
<el-table :data="tableData"
border
row-key="id"
align="left">
<el-table-column v-for="(item, index) in col"
:key="`col_${index}`"
:prop="dropCol[index].prop"
:label="item.label">
</el-table-column>
</el-table>
<pre style="text-align: left">
{{dropCol}}
</pre>
<hr>
<pre style="text-align: left">
{{tableData}}
</pre>
</div>
</template>
<script>
import Sortable from 'sortablejs'
export default {
data() {
return {
col: [
{
label: '日期',
prop: 'date'
},
{
label: '姓名',
prop: 'name'
},
{
label: '地址',
prop: 'address'
}
],
dropCol: [
{
label: '日期',
prop: 'date'
},
{
label: '姓名',
prop: 'name'
},
{
label: '地址',
prop: 'address'
}
],
tableData: [
{
id: '1',
date: '2016-05-02',
name: '王小虎1',
address: '上海市普陀区金沙江路 100 弄'
},
{
id: '2',
date: '2016-05-04',
name: '王小虎2',
address: '上海市普陀区金沙江路 200 弄'
},
{
id: '3',
date: '2016-05-01',
name: '王小虎3',
address: '上海市普陀区金沙江路 300 弄'
},
{
id: '4',
date: '2016-05-03',
name: '王小虎4',
address: '上海市普陀区金沙江路 400 弄'
}
]
}
},
mounted() {
this.rowDrop()
this.columnDrop()
},
methods: {
//行拖拽
rowDrop() {
const tbody = document.querySelector('.el-table__body-wrapper tbody')
const _this = this
Sortable.create(tbody, {
onEnd({ newIndex, oldIndex }) {
const currRow = _this.tableData.splice(oldIndex, 1)[0]
_this.tableData.splice(newIndex, 0, currRow)
}
})
},
//列拖拽
columnDrop() {
const wrapperTr = document.querySelector('.el-table__header-wrapper tr')
this.sortable = Sortable.create(wrapperTr, {
animation: 180,
delay: 0,
onEnd: evt => {
const oldItem = this.dropCol[evt.oldIndex]
this.dropCol.splice(evt.oldIndex, 1)
this.dropCol.splice(evt.newIndex, 0, oldItem)
}
})
}
}
}
</script>
<style scoped>
</style>
element ui table Sortable.js

Problem with expandable child component in parent v-data-table using Vuetify 2

I upgraded to Vuetify 2 from 1.5. Everything went pretty smoothly except for one thing. I have a parent component with a v-data-table and I want to pass data and expand each row with a child component.
ScanGrid(parent component):
<template>
<v-container>
<v-card>
<v-card-text>
<v-layout row align-center>
<v-data-table
:headers="headers"
:items="items"
:hide-default-footer="true"
item-key="id"
>
<template slot="items" slot-scope="props">
<tr #click="props.expanded = !props.expanded">
<td>{{ props.item.name }}</td>
<td class="text-xs-left large-column">
{{ props.item.scanned }}
</td>
<td class="text-xs-left large-column">
{{ props.item.incoming }}
</td>
<td class="text-xs-left large-column">
{{ props.item.outgoing }}
</td>
<td class="text-xs-left large-column">
{{ props.item.unknown }}
</td>
</tr>
</template>
<template slot="expand" slot-scope="props">
<ScanGridChild :value="props.item"></ScanGridChild>
</template>
</v-data-table>
</v-layout>
</v-card-text>
</v-card>
</v-container>
</template>
ScanGridChild(child component):
<template>
<v-card>
<v-card-text>{{ value }}</v-card-text>
</v-card>
</template>
<script>
export default {
name: "ScanGridChildComponent",
props: {
value: {
Type: Object,
Required: true
}
},
computed: {},
watch: {
props: function(newVal, oldVal) {
console.log("Prop changed: ", newVal, " | was: ", oldVal);
this.render();
}
}
};
</script>
<style></style>
It worked fine in Vuetify 1.5.19. I'm on Vuetify 2.1.6 and using single file components. Thanks.
Vuetify 2.x has major changes to many components, slot-scopes are replaced with v-slot, and many new properties and slots added to vuetify data table
Here is the working codepen reproduced the same feature with above code
https://codepen.io/chansv/pen/BaaWbKR?editors=1010
You need to make sure that you have vue js 2.x and vuetify 2.x
Parent component code:
<template>
<v-container>
<v-card>
<v-card-text>
<v-layout row align-center>
<v-data-table
:headers="headers"
:items="items"
item-key="name"
single-expand
:expanded="expanded"
hide-default-footer
#click:row="clickedRow"
>
<template v-slot:expanded-item="{ item }">
<td :colspan="headers.length">
<ScanGridChild :value="item"></ScanGridChild>
</td>
</template>
</v-data-table>
</v-layout>
</v-card-text>
</v-card>
</v-container>
</template>
<script>
export default {
...
data () {
return {
expanded: [],
headers: [
{
text: "Localisation",
sortable: true,
value: "name"
},
{
text: "Paquets scannés",
sortable: true,
value: "scanned"
},
{
text: "Paquets entrants",
sortable: true,
value: "incoming"
},
{
text: "Paquets sortants",
sortable: true,
value: "outgoing"
},
{
text: "Paquets inconnus",
sortable: true,
value: "unknown"
}
],
items: [
{
id: 1,
name: "Location 1",
scanned: 159,
incoming: 6,
outgoing: 24,
unknown: 4,
test: "Test 1"
},
{
id: 2,
name: "Location 2",
scanned: 45,
incoming: 6,
outgoing: 24,
unknown: 4,
test: "Test 2"
}
],
}
},
methods: {
clickedRow(value) {
if (this.expanded.length && this.expanded[0].id == value.id) {
this.expanded = [];
} else {
this.expanded = [];
this.expanded.push(value);
}
}
}
...
}
</script>
In child component
Replace
props: {
value: {
Type: Object,
Required: true
}
},
with( Type and Required change to lower case type and required)
props: {
value: {
type: Object,
required: true
}
},

Auto select rows in v-data-table

I would like to programmatically checkmark a row in a v-data-table when an external listener notifies me of a particular value.
As an example, here is a Vuetify selectable table: https://vuetifyjs.com/en/components/data-tables#selectable-rows
In the example, If I were passed the value of 'Gingerbread' after the table and its data have already been instantiated, how would I programmatically select that corresponding row?
You can do this by pushing your values in your model like this:
HTML:
<div id="app">
<v-app id="inspire">
<v-btn #click="select">button</v-btn>
<v-data-table
v-model="selected"
:headers="headers"
:items="desserts"
:single-select="singleSelect"
item-key="name"
show-select
class="elevation-1"
>
<template v-slot:top>
<v-switch v-model="singleSelect" label="Single select" class="pa-3"></v-switch>
</template>
</v-data-table>
</v-app>
</div>
VueJS:
new Vue({
el: '#app',
vuetify: new Vuetify(),
methods: {
select: function() {
let result = this.desserts.find((dessert) => {
return dessert.name == 'Gingerbread'
})
this.selected.push(result)
}
},
data () {
return {
singleSelect: false,
selected: [],
headers: [
{ text: 'Dessert (100g serving)', value: 'name' },
{ text: 'Calories', value: 'calories' },
],
desserts: [
{ name: 'Gingerbread', calories: 356 },
{ name: 'Jelly bean', calories: 375 }
],
}
},
})
The v-data-table component has a property called filteredItems which you can use to add items to the selected array
<v-data-table v-model="selected":items="itemsArray" ref="table"></v-data-table>
function selectAll() {
this.$refs.table.filteredItems.map(item => {
if(...some condition...) {
this.selected.push(item)
}
})
}

Vuetify 2.x: v-data-table expand row on click

I am using Vuetify.js and I am creating a a v-data-table
I cannot figure out how to expand a row by clicking anywhere on it, it seems that the only possibility is by using the show-expand property and clicking the icon
Final solution
As suggested here, the v-data-table can link an array to its expanded property, so if you push any item from the table, to this array, it will expand the corresponding row. Intuitive and smart
<template>
<v-data-table
:headers="headers"
:items="items"
:expanded="expanded"
item-key="id"
#click:row="expandRow"
/>
</template>
<script>
data () {
return {
expanded: [],
}
},
expandRow (item) {
// would be
// this.expanded = [item]
// but if you click an expanded row, you want it to collapse
this.expanded = item === this.expanded[0] ? [] : [item]
},
</script>
It worked for me:
<v-data-table
...
#click:row="(item, slot) => slot.expand(!slot.isExpanded)"
/>
Api docs here
There is a click event which gives you the current row on the v-data-table. This one you can use. In the event you update the expanded value
Like this:
HTML:
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="desserts"
:expanded="expanded"
item-key="name"
show-expand
class="elevation-1"
#click:row="clicked">
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>Expandable Table</v-toolbar-title>
<div class="flex-grow-1"></div>
<v-switch v-model="singleExpand" label="Single expand" class="mt-2"></v-switch>
</v-toolbar>
</template>
<template v-slot:expanded-item="{ headers }">
<td :colspan="headers.length">Peek-a-boo!</td>
</template>
</v-data-table>
</v-app>
</div>
vue js:
new Vue({
el: '#app',
vuetify: new Vuetify(),
methods: {
clicked(value) {
this.expanded.push(value)
}
},
data () {
return {
expanded: ['Donut'],
singleExpand: false,
headers: [
{
text: 'Dessert (100g serving)',
align: 'left',
sortable: false,
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' },
],
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%',
}
],
}
},
})
i am not sure if you still need this :P but i wanted to improve dreijntjens reply for people who see this post
so add a listener attr
<v-data-table
:headers="headers"
:items="desserts"
:expanded="expanded"
item-key="name"
show-expand
class="elevation-1"
#click:row="clicked">
and add this method
clicked (value) {
const index = this.expanded.indexOf(value)
if (index === -1) {
this.expanded.push(value)
} else {
this.expanded.splice(index, 1)
}
},
my method will actually both expand and close on click
If you are using v-slot:item, or you set the prop :hide-default-header="true", then you can implement it this way:
<template v-slot:item="{item, index}">
<tr #click="expandedIndex = expandedIndex==-1?index:-1">
<span> {{item}} </span>
</tr>
<tr :colspan="headers.length" v-if="expandedIndex==index">Expanded content</tr>
</template>
If you want to be able to expand multiple rows at the same time, you can do this:
<v-data-table :headers="headers" :items="items">
<template v-slot:item="{item, index}">
<tr #click="expandRow(index)">
<span> {{item}} </span>
</tr>
<tr v-if="expandedRows.includes(index)">
<td :colspan="headers.length">
Expanded content
</td>
</tr>
</template>
</v-data-table>
<script>
...
...
expandedRows=[];
expandRow(index){
const indexOfRow = this.expandedRows.indexOf(index)
if(indexOfRow>-1){
this.expandedRows.splice(indexOfRow,1);
return;
}
this.expandedRows.push(index);
}
</script>

Resources