Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(VDataTable): Feat/emit sorted and filtered items v data table #19382

Open
wants to merge 18 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/api-generator/src/locale/en/VDataTable.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"pagination": "Emits when something changed to the `pagination` which can be provided via the `pagination` prop.",
"toggleSelectAll": "Emits when the `select-all` checkbox in table header is clicked. This checkbox is enabled by the **show-select** prop.",
"update:expanded": "Emits when the **expanded** property of the **options** prop is updated.",
"update:filteredItems": "Emits i.e. when **searching** and return the filtered items.",
"update:groupBy": "Emits when the **group-by** property of the **options** property is updated.",
"update:groupDesc": "Emits when the **group-desc** property of the **options** prop is updated.",
"update:itemsPerPage": "Emits when the **items-per-page** property of the **options** prop is updated.",
Expand All @@ -82,6 +83,7 @@
"update:options": "Emits when one of the **options** properties is updated.",
"update:page": "Emits when the **page** property of the **options** prop is updated.",
"update:sortBy": "Emits when the **sortBy** property of the **options** prop is updated.",
"update:sortDesc": "Emits when the **sort-desc** property of the **options** prop is updated."
"update:sortDesc": "Emits when the **sort-desc** property of the **options** prop is updated.",
"update:sortedItems": "Emits when **sorting** and return items according to its current sorting."
}
}
2 changes: 2 additions & 0 deletions packages/vuetify/src/components/VDataTable/VDataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ export const VDataTable = genericComponent<new <T extends readonly any[], V>(
'update:groupBy': (value: any) => true,
'update:expanded': (value: any) => true,
'update:currentItems': (value: any) => true,
'update:sortedItems': (value: any) => true,
'update:filteredItems': (value: any) => true,
},

setup (props, { attrs, slots }) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { useLocale } from '@/composables'
import { useProxiedModel } from '@/composables/proxiedModel'

// Utilities
import { computed, inject, provide, toRef } from 'vue'
import { getObjectValueByPath, isEmpty, propsFactory } from '@/util'
import { computed, inject, provide, toRef, watch } from 'vue'
import { getCurrentInstance, getObjectValueByPath, isEmpty, propsFactory } from '@/util'

// Types
import type { InjectionKey, PropType, Ref } from 'vue'
Expand Down Expand Up @@ -101,6 +101,7 @@ export function useSortedItems <T extends Record<string, any>> (
sortFunctions?: Ref<Record<string, DataTableCompareFunction> | undefined>,
sortRawFunctions?: Ref<Record<string, DataTableCompareFunction> | undefined>,
) {
const vm = getCurrentInstance('userSortedItems')
const locale = useLocale()
const sortedItems = computed(() => {
if (!sortBy.value.length) return items.value
Expand All @@ -111,6 +112,10 @@ export function useSortedItems <T extends Record<string, any>> (
}, sortRawFunctions?.value)
})

watch(sortedItems, val => {
vm.emit('update:sortedItems', val)
})

return { sortedItems }
}

Expand Down
17 changes: 10 additions & 7 deletions packages/vuetify/src/composables/__tests__/filter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { transformItem, transformItems } from '../list-items'
// Utilities
import { describe, expect, it } from '@jest/globals'
import { nextTick, ref } from 'vue'
import { withSetup } from '../../util/withSetup'
import { deepEqual } from '@/util'

const itemProps = {
Expand Down Expand Up @@ -132,9 +133,8 @@ describe('filter', () => {
['14', 1],
['foo', 0],
])('should return an array of filtered items from value %s', (text: any, expected: number) => {
const { filteredItems } = useFilter({}, ref(transformItems(itemProps, items)), ref(text))

expect(filteredItems.value).toHaveLength(expected)
const [result] = withSetup(() => useFilter({}, ref(transformItems(itemProps, items)), ref(text)))
expect((result as any)?.filteredItems?.value).toHaveLength(expected)
})

it('should accept a custom filter function', async () => {
Expand All @@ -150,19 +150,22 @@ describe('filter', () => {
{ title: 'fizz' },
{ title: 'buzz' },
]))
const { filteredItems } = useFilter(props, items, query)

expect(filteredItems.value.map(item => item.raw.title)).toEqual(['fizz', 'buzz'])
const [result] = withSetup(() => useFilter(props, items, query))

const filteredItems = (result as any)?.filteredItems

expect(filteredItems.value.map((item: any) => item.raw.title)).toEqual(['fizz', 'buzz'])

query.value = 'foo'
await nextTick()

expect(filteredItems.value.map(item => item.raw.title)).toEqual(['foo'])
expect(filteredItems.value.map((item: any) => item.raw.title)).toEqual(['foo'])

items.value.push(transformItem(itemProps, { title: 'foobar' }))
await nextTick()

expect(filteredItems.value.map(item => item.raw.title)).toEqual(['foo', 'foobar'])
expect(filteredItems.value.map((item: any) => item.raw.title)).toEqual(['foo', 'foobar'])
})
})
})
5 changes: 4 additions & 1 deletion packages/vuetify/src/composables/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

// Utilities
import { computed, ref, unref, watchEffect } from 'vue'
import { getPropertyFromItem, propsFactory, wrapInArray } from '@/util'
import { getCurrentInstance, getPropertyFromItem, propsFactory, wrapInArray } from '@/util'

// Types
import type { PropType, Ref } from 'vue'
Expand Down Expand Up @@ -139,6 +139,7 @@ export function useFilter <T extends InternalItem> (
customKeyFilter?: MaybeRef<FilterKeyFunctions | undefined>
}
) {
const vm = getCurrentInstance('useFilter')
const filteredItems: Ref<T[]> = ref([])
const filteredMatches: Ref<Map<unknown, Record<string, FilterMatch>>> = ref(new Map())
const transformedItems = computed(() => (
Expand Down Expand Up @@ -180,6 +181,8 @@ export function useFilter <T extends InternalItem> (
})
filteredItems.value = _filteredItems
filteredMatches.value = _filteredMatches

vm.emit('update:filteredItems', filteredItems.value)
})

function getMatches (item: T) {
Expand Down
18 changes: 18 additions & 0 deletions packages/vuetify/src/util/withSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* From vuejs.org docs: https://vuejs.org/guide/scaling-up/testing.html#testing-composables */
// Utilities
import { createApp } from 'vue'

export function withSetup (composable: any) {
let result
const app = createApp({
setup () {
result = composable()
// suppress missing template warning
return () => { }
},
})
app.mount(document.createElement('div'))
// return the result and the app instance
// for testing provide/unmount
return [result, app]
}