Skip to content

Commit 80cb876

Browse files
authored
feat(VDataTable): re-introduce group-summary slot (#21802)
resolves #21800
1 parent 739a6c9 commit 80cb876

File tree

16 files changed

+164
-28
lines changed

16 files changed

+164
-28
lines changed

packages/api-generator/src/locale/en/VDataIterator.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"disableSort": "Disables sorting completely.",
99
"expanded": "Array of expanded items. Can be used with `.sync` modifier.",
1010
"footerProps": "See the [`v-data-footer`](/api/v-data-footer) API for more information.",
11-
"groupBy": "Configures attributes (and sort order) to group items together. Can be customized further with `group-header` slot.",
11+
"groupBy": "Configures attributes (and sort order) to group items together.",
1212
"hideDefaultFooter": "Hides default footer.",
1313
"itemKey": "The property on each item that is used as a unique key.",
1414
"itemsPerPage": "Changes how many items per page should be visible. Can be used with `.sync` modifier. Setting this prop to `-1` will display all items on the page.",

packages/api-generator/src/locale/en/VDataTable.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"disableSort": "Disables sorting completely.",
1313
"expandIcon": "Icon used for expand toggle button.",
1414
"fixedHeader": "Fixed header to top of table.",
15-
"groupBy": "Configures attributes (and sort order) to group items together. Can be customized further with `group-header` slot.",
15+
"groupBy": "Configures attributes (and sort order) to group items together. Can be customized further with `group-header` and `group-summary` slots.",
1616
"headerProps": "Pass props to the default header. See [`v-data-table-headers` API](/api/v-data-table-headers) for more information.",
1717
"headers": "An array of objects that each describe a header column.",
1818
"headersLength": "Can be used in combination with `hide-default-header` to specify the number of columns in the table to allow expansion rows and loading bar to function properly.",
@@ -48,8 +48,8 @@
4848
"footer.prepend": "Adds content to the empty space in the footer.",
4949
"footer.page-text": "Slot to customize footer page text.",
5050
"group": "Slot to replace the default rendering of grouped rows.",
51-
"group.header": "Slot to customize the default rendering of group headers.",
52-
"group.summary": "Slot to customize the default rendering of group summaries.",
51+
"group-header": "Slot for custom rendering of a group header.",
52+
"group-summary": "Slot for custom rendering of a group summary.",
5353
"heading": "Slot to add a custom header.",
5454
"header.<name>": "Slot to customize a specific header column.",
5555
"header.data-table-select": "Slot to replace the default `v-checkbox-btn` in header.",

packages/api-generator/src/locale/en/VDataTableRows.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"data-table-select": "Slot for custom rendering of a header cell with the select checkbox.",
1919
"expanded-row": "Slot for custom rendering of an expanded row.",
2020
"group-header": "Slot for custom rendering of a group header.",
21+
"group-summary": "Slot for custom rendering of a group summary.",
2122
"item.data-table-expand": "Slot for custom rendering of a row cell with the expand icon.",
2223
"item.data-table-select": "Slot for custom rendering of a row cell with the select checkbox.",
2324
"loading": "Slot for custom rendering of the loading state."

packages/api-generator/src/locale/en/VDataTableServer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"expanded-row": "Slot for custom rendering of an expanded row.",
2323
"footer.prepend": "Adds content to the empty space in the footer.",
2424
"group-header": "Slot for custom rendering of a group header.",
25+
"group-summary": "Slot for custom rendering of a group summary.",
2526
"headers": "Slot to replace the default rendering of the `<thead>` element.",
2627
"item": "Slot to replace the default rendering of a row.",
2728
"item.data-table-expand": "Slot to replace the default `v-icon` used when expanding rows.",

packages/api-generator/src/locale/en/VDataTableVirtual.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"disableSort": "Disables sorting completely.",
2222
"expanded-row": "Slot for custom rendering of an expanded row.",
2323
"group-header": "Slot for custom rendering of a group header.",
24+
"group-summary": "Slot for custom rendering of a group summary.",
2425
"headers": "Slot to replace the default rendering of the `<thead>` element.",
2526
"item": "Slot to replace the default rendering of a row.",
2627
"item.data-table-expand": "Slot to replace the default `v-icon` used when expanding rows.",

packages/docs/src/data/new-in.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@
6363
"VDataTable": {
6464
"props": {
6565
"headerProps": "3.5.0"
66+
},
67+
"slots": {
68+
"group-summary": "3.9.4"
69+
}
70+
},
71+
"VDataTableServer": {
72+
"slots": {
73+
"group-summary": "3.9.4"
74+
}
75+
},
76+
"VDataTableVirtual": {
77+
"slots": {
78+
"group-summary": "3.9.4"
6679
}
6780
},
6881
"VExpansionPanels": {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<template>
2+
<v-data-table
3+
:group-by="groupBy"
4+
:headers="headers"
5+
:items="tools"
6+
:items-per-page="-1"
7+
item-value="name"
8+
hide-default-footer
9+
>
10+
<template v-slot:group-summary="{ item, columns }">
11+
<tr class="font-weight-bold text-red">
12+
<td v-for="c in columns" :key="c.key" :class="['v-data-table__td', c.align ? `v-data-table-column--align-${c.align}` : '']">
13+
<span v-if="c.key === 'name'">Totals</span>
14+
<span v-if="c.key === 'weight'">{{ item.items.reduce((sum, n) => sum + n.raw.weight, 0) }}</span>
15+
<span v-if="c.key === 'length'">{{ item.items.reduce((sum, n) => sum + n.raw.length, 0) }}</span>
16+
<span v-if="c.key === 'price'">{{ item.items.reduce((sum, n) => sum + n.raw.price, 0) }}</span>
17+
</td>
18+
</tr>
19+
</template>
20+
</v-data-table>
21+
</template>
22+
23+
<script setup>
24+
const groupBy = [{ key: 'type', order: 'asc' }]
25+
26+
const headers = [
27+
{ title: 'Tool Name', sortable: false, key: 'name' },
28+
{ title: 'Weight(kg)', key: 'weight', align: 'end' },
29+
{ title: 'Length(cm)', key: 'length', align: 'end' },
30+
{ title: 'Price($)', key: 'price', align: 'end' },
31+
]
32+
33+
const tools = [
34+
{ name: 'Hammer', weight: 0.5, length: 30, price: 10, type: 'hand' },
35+
{ name: 'Screwdriver', weight: 0.2, length: 20, price: 5, type: 'hand' },
36+
{ name: 'Drill', weight: 1.5, length: 25, price: 50, type: 'power' },
37+
{ name: 'Saw', weight: 0.7, length: 50, price: 15, type: 'hand' },
38+
{ name: 'Tape Measure', weight: 0.3, length: 10, price: 8, type: 'measuring' },
39+
{ name: 'Level', weight: 0.4, length: 60, price: 12, type: 'measuring' },
40+
{ name: 'Wrench', weight: 0.6, length: 25, price: 10, type: 'hand' },
41+
{ name: 'Pliers', weight: 0.3, length: 15, price: 7, type: 'hand' },
42+
{ name: 'Sander', weight: 2.0, length: 30, price: 60, type: 'power' },
43+
{ name: 'Multimeter', weight: 0.5, length: 15, price: 30, type: 'measuring' },
44+
]
45+
</script>
46+
47+
<script>
48+
export default {
49+
data () {
50+
return {
51+
groupBy: [{ key: 'type', order: 'asc' }],
52+
headers: [
53+
{ title: 'Tool Name', sortable: false, key: 'name' },
54+
{ title: 'Weight(kg)', key: 'weight', align: 'end' },
55+
{ title: 'Length(cm)', key: 'length', align: 'end' },
56+
{ title: 'Price($)', key: 'price', align: 'end' },
57+
],
58+
tools: [
59+
{ name: 'Hammer', weight: 0.5, length: 30, price: 10, type: 'hand' },
60+
{ name: 'Screwdriver', weight: 0.2, length: 20, price: 5, type: 'hand' },
61+
{ name: 'Drill', weight: 1.5, length: 25, price: 50, type: 'power' },
62+
{ name: 'Saw', weight: 0.7, length: 50, price: 15, type: 'hand' },
63+
{ name: 'Tape Measure', weight: 0.3, length: 10, price: 8, type: 'measuring' },
64+
{ name: 'Level', weight: 0.4, length: 60, price: 12, type: 'measuring' },
65+
{ name: 'Wrench', weight: 0.6, length: 25, price: 10, type: 'hand' },
66+
{ name: 'Pliers', weight: 0.3, length: 15, price: 7, type: 'hand' },
67+
{ name: 'Sander', weight: 2.0, length: 30, price: 60, type: 'power' },
68+
{ name: 'Multimeter', weight: 0.5, length: 15, price: 30, type: 'measuring' },
69+
],
70+
}
71+
},
72+
}
73+
</script>

packages/docs/src/pages/en/components/data-tables/basics.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,16 @@ When using the **group-by** prop, you can customize the group header with the `g
214214

215215
<ExamplesExample file="v-data-table/slot-group-header" />
216216

217+
#### Group summary slot
218+
219+
::: info
220+
This feature requires [v3.9.4](/getting-started/release-notes/?version=v3.9.4)
221+
:::
222+
223+
By default grouping with **group-by** shows only the header slot. When you define `group-summary` slot, additional summary row will appear below the group rows.
224+
225+
<ExamplesExample file="v-data-table/slot-group-summary" />
226+
217227
#### Loading slot
218228

219229
The `loading` slot allows you to customize your table's display state when fetching data. In this example we utilize the [v-skeleton-loader](/components/skeleton-loaders) component to display a loading animation.

packages/vuetify/src/components/VDataIterator/VDataIterator.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { genericComponent, propsFactory, useRender } from '@/util'
2828
// Types
2929
import type { Component } from 'vue'
3030
import type { DataIteratorItem } from './composables/items'
31-
import type { Group } from '@/components/VDataTable/composables/group'
31+
import type { Group, GroupSummary } from '@/components/VDataTable/composables/group'
3232
import type { SortItem } from '@/components/VDataTable/composables/sort'
3333
import type { LoaderSlotProps } from '@/composables/loader'
3434
import type { GenericProps } from '@/util'
@@ -52,7 +52,7 @@ type VDataIteratorSlotProps<T> = {
5252
isGroupOpen: ReturnType<typeof provideGroupBy>['isGroupOpen']
5353
toggleGroup: ReturnType<typeof provideGroupBy>['toggleGroup']
5454
items: readonly DataIteratorItem<T>[]
55-
groupedItems: readonly (DataIteratorItem<T> | Group<DataIteratorItem<T>>)[]
55+
groupedItems: readonly (DataIteratorItem<T> | Group<DataIteratorItem<T>> | GroupSummary<DataIteratorItem<T>>)[]
5656
}
5757

5858
export type VDataIteratorSlots<T> = {
@@ -119,7 +119,7 @@ export const VDataIterator = genericComponent<new <T> (
119119
const { sortByWithGroups, opened, extractRows, isGroupOpen, toggleGroup } = provideGroupBy({ groupBy, sortBy })
120120

121121
const { sortedItems } = useSortedItems(props, filteredItems, sortByWithGroups, { transform: item => item.raw })
122-
const { flatItems } = useGroupedItems(sortedItems, groupBy, opened)
122+
const { flatItems } = useGroupedItems(sortedItems, groupBy, opened, false)
123123

124124
const itemsLength = toRef(() => flatItems.value.length)
125125

packages/vuetify/src/components/VDataTable/VDataTable.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { genericComponent, propsFactory, useRender } from '@/util'
2626

2727
// Types
2828
import type { DeepReadonly, UnwrapRef } from 'vue'
29-
import type { Group } from './composables/group'
29+
import type { Group, GroupSummary } from './composables/group'
3030
import type { CellProps, DataTableHeader, DataTableItem, InternalDataTableHeader, RowProps } from './types'
3131
import type { VDataTableHeadersSlots } from './VDataTableHeaders'
3232
import type { VDataTableRowsSlots } from './VDataTableRows'
@@ -51,7 +51,7 @@ export type VDataTableSlotProps<T> = {
5151
toggleGroup: ReturnType<typeof provideGroupBy>['toggleGroup']
5252
items: readonly T[]
5353
internalItems: readonly DataTableItem[]
54-
groupedItems: readonly (DataTableItem<T> | Group<DataTableItem<T>>)[]
54+
groupedItems: readonly (DataTableItem<T> | Group<DataTableItem<T>> | GroupSummary<DataTableItem<T>>)[]
5555
columns: InternalDataTableHeader[]
5656
headers: InternalDataTableHeader[][]
5757
}
@@ -160,7 +160,7 @@ export const VDataTable = genericComponent<new <T extends readonly any[], V>(
160160
sortFunctions,
161161
sortRawFunctions,
162162
})
163-
const { flatItems } = useGroupedItems(sortedItems, groupBy, opened)
163+
const { flatItems } = useGroupedItems(sortedItems, groupBy, opened, () => !!slots['group-summary'])
164164
const itemsLength = computed(() => flatItems.value.length)
165165

166166
const { startIndex, stopIndex, pageCount, setItemsPerPage } = providePagination({ page, itemsPerPage, itemsLength })

0 commit comments

Comments
 (0)