Good Morning,
I am trying to do and edit feature in a Quasar table.
It works as expected, but when I have more than one entry in the table it defaults to the last entry.
The value of the row is added to the component using props, my problem is getting the current row.
So my question is how do it get the correct row when clicking the button?
Code Download
You can get row data using props.row.
Example -
<q-table
title="Treats"
:data="data"
:columns="columns"
row-key="name"
>
<template v-slot:body-cell-name="props">
<q-td :props="props">
<div>
<q-badge color="purple" :label="props.value"></q-badge>
<q-btn icon="edit" dense flat size="sm" #click="EditData(props.row)"></q-btn>
</div>
</q-td>
</template>
</q-table>
methods:{
EditData(row){
alert("hi")
console.log(row);
console.log(this.data.indexOf(row))
}
}
Now you have a row and indexof particular row. You can use splice or replace the element on particular index.
Codepen - https://codepen.io/Pratik__007/pen/LYVjqXb
Check the console.
**you can use index to get the row number
<tr v-for="(strockorder,index) in strockorders" :key="index">
<td class="text-left">{{ strockorder.strockNo}}</td>
<td class="text-center">{{ strockorder.item}}</td>
<td class="text-center">{{ strockorder.orderDate}} </td>
<td class="text-center">{{strockorder.deliveryDate }}</td>
**
Related
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
I am working with a vuetify data table, I am using the groub-by slot to group my items either by category or location that is working fine. What I am trying to do now is add a summary row for each group.
this is my current code for the grouping and attempt at summary row
<v-data-table
v-if="reportType === 'Category' || reportType === 'Location'"
:headers="headers"
:items="assets"
disable-pagination
disable-filtering
hide-default-footer
disable-sort
:group-by="`${reportType.toLowerCase()}Name`"
class="elevation-1">
<template v-slot:group="{ items }">
<tr>
<td class="text-xs-right" :colspan="fixGroupByHeaders()"><strong>{{ getGroupByName(items[0]) }}</strong></td>
</tr>
<tr v-for="(item) in items" :key="item.id">
<td v-for="(header, index) in headers" :key="index">
{{ (getTotalCost(item, header.value) || item[header.value]) }}
</td>
</tr>
</template>
<template v-slot:group.summary="{ items }">
<tr>
<th class="title">Totals</th>
</tr>
</template>
</v-data-table>
the groupby is working but th e summary is not .. I would like to know what I am doing wrong and how can I fix it to where I get the summary row using the grouby.summary slot found on the vuetify data table api.
EDIT:
I understand about the group.summary slot and I can easily make it if the report headers were static, in this case they are not.
So, I created a CodeSandbox example that I hope will show you what I am trying to achieve and as I said the headers array is dynamic.
Another thing is I added an array called columnsToTotal to show what columns need a total added if they are present in the headers array.
You can't use both group and group.summary slots simultaneously.
group.header and group.summary slots is just a "sub-slots" of group slot. When you are overriding group slot, the "sub-slots" simply does not exist.
I'm not clearly understand what are you trying to achieve, but perhaps this tip will be useful to you.
If you want to customize...
...your group header, use group.header slot
...your group rows, use item slot
...your group footer, use group.summary slot
...the whole group, use group slot
This is what I did to get my summary row. itemTotal is a method.
<template v-slot:group.summary="{ items }">
<th colspan="7"></th>
<th>
<span class="ml-10">
Charge Total: {{ itemTotal(items) }}
</span>
</th>
</template>
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.
I have a Vuetify data table with expandable rows. Each row correlates with a customer's order which consists of samples they want to be tested.
Currently, I'm retrieving all the orders with all the samples but it takes too long to load all the information.
So instead of retrieving all the samples for every order, when I expand a row I want to be able to perform an API call to retrieve the samples that should be displayed in the expanded section for that particular order.
I've researched all I can and have come to a dead-end. Here's where I'm at currently:
<v-data-table
:headers="orders_headers"
:items="orders"
show-expand
:single-expand="true"
:expanded.sync="expanded"
>
<!-- Expand Buttons -->
<template v-slot:item.data-table-expand="{ item, isExpanded, expand }">
<v-btn #click="expand(true)" v-if="!isExpanded">Expand</v-btn>
<v-btn #click="expand(false)" v-if="isExpanded">close</v-btn>
</template>
<!-- Expanded Data -->
<template v-slot:expanded-item="{ headers, item }">
<td :colspan="headers.length">
<table v-for="(sample, index) in item.samples" :key="index">
<tr>
<th>Sample Acc</th>
<td>{{ sample.sample_accession }}</td>
</tr>
<tr>
<th>Sample Status</th>
<td>{{ sample.sample_status }}</td>
</tr>
</table>
</td>
</template>
</v-data-table>
I think I may have figured it while writing this
As I was typing this out, I realized what I possibly need to do. I need to add a method call to the expand button, then in that method set the results to expandedSamples and replace item.samples with it.
In the meantime, if anyone has any better solution I'd love to hear. Otherwise, I'll post my solution in case anyone else is trying to attempt something similar to this.
Bonus
Anyone know if there's a way to tap into the expand event without replacing the default icons/functionality or a way to include the original icons/functionality when using v-slot:item.data-table-expand?
Currently when I'm using v-slot:item.data-table-expand, I have to add the buttons back in and I lose the chevrons and the animations.
For the benefit of future readers facing the same issue, use the #item-expanded event of the data-table to lazy load the item details (or child data) on demand. Hook the item-expanded event to a method (e.g. loadDetails) that loads the data, and then merges the response into the original items array.
Here's an example...
<v-data-table
:headers="headers"
:items="items"
show-expand
single-expand
item-key="name"
:search="search"
#item-expanded="loadDetails"
>
<template v-slot:expanded-item="{ headers, item }">
<td :colspan="headers.length">
<table v-for="(sample, index) in items.samples" :key="index">
<tr>
<th>Sample Acc</th>
<td>{{ sample.sample_accession }}</td>
</tr>
</table>
</td>
</template>
</v-data-table>
methods: {
loadDetails({item}) {
axios.get('http.../' + item.id)
.then(response => {
item.samples = response.data[0]
})
}
}
https://codeply.com/p/d5XibmqjUh
Here's the basic solution to my issue.
<v-data-table
:headers="orders_headers"
:items="orders"
show-expand
:single-expand="true"
:expanded.sync="expanded"
>
<!-- Expand Buttons -->
<template v-slot:item.data-table-expand="{ item, isExpanded, expand }">
<v-btn #click="expand(true); getSamples(item.id)" v-if="!isExpanded">Expand</v-btn>
<v-btn #click="expand(false)" v-if="isExpanded">close</v-btn>
</template>
<!-- Expanded Data -->
<template v-slot:expanded-item="{ headers, item }">
<td :colspan="headers.length">
<table v-for="(sample, index) in expandedOrderDetails" :key="index">
<tr>
<th>Sample Acc</th>
<td>{{ sample.sample_accession }}</td>
</tr>
<tr>
<th>Sample Status</th>
<td>{{ sample.sample_status }}</td>
</tr>
</table>
</td>
</template>
</v-data-table>
<script>
methods: {
getSamples(orderId) {
// Perform API call
this.expandedOrderDetails = response.data;
},
}
</script>
After many hours of development, our project leader has decided he wants each row to correlate to each sample instead of orders though. So expanding is no longer necessary.
I would like to iterate rows in a table based over a range. But all examples I've seen show how to do this for a constant for example,
<div>
<span v-for="n in 10">{{ n }} </span>
</di
How can I do this for a variable similar to this,
<table>
<tr v-for="(el, index) in form.repeat" :key="index">
<td>hello</td>
</tr>
</table>
This variable form.repeat is set in a form on the page.
Thanks
I had this issue week, my workaround for it was setting a variable in your data section to the number of rows you want. In my case based on the number of devices my backend returned the length of the list as part of the response. When Vue receives this response. I assign the variable that I created earlier in my data section to this number and I plug that into my v-for loop.
In the data section:
data: () => ({'num_pis': 0})
In the template part, reference the number. This is just a snippet, I'm using a v-data-table from Vuetify.
<template slot="items" slot-scope="props">
<td class="table-content-style">{{ props.item.metric_name }}</td>
<td v-for="i in num_pis">
{{ props.item[i] }}
</td>
</template>
Codepen Example