From e639891616fb5d2589c6989c2f63aef14bf9c84d Mon Sep 17 00:00:00 2001 From: Prashant Singh Bisht Date: Tue, 15 Aug 2023 13:21:00 +0530 Subject: [PATCH] feat(VSelect/VAutocomplete/VCombobox): Add onChange event resolves #14151 --- .../components/VAutocomplete/VAutocomplete.tsx | 14 +++++++++++++- .../src/components/VCombobox/VCombobox.tsx | 18 ++++++++++++++---- .../vuetify/src/components/VSelect/VSelect.tsx | 17 +++++++++++++++-- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx b/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx index b696fb07f75..58dc56295fe 100644 --- a/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx +++ b/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx @@ -109,9 +109,10 @@ export const VAutocomplete = genericComponent true, 'update:modelValue': (val: any) => true, 'update:menu': (val: boolean) => true, + 'change': (selected: any, added: any, removed: any) => true, }, - setup (props, { slots }) { + setup (props, { emit, slots }) { const { t } = useLocale() const vTextFieldRef = ref() const isFocused = shallowRef(false) @@ -365,6 +366,17 @@ export const VAutocomplete = genericComponent { + emit('change', + model.value.map(v => v.props.value), + val.filter(v => !oldVal.includes(v)).map(v => v.props.value), + oldVal.filter(v => !val.includes(v)).map(v => v.props.value) + ) + } + ) + watch(search, val => { if (!isFocused.value || isSelecting.value) return diff --git a/packages/vuetify/src/components/VCombobox/VCombobox.tsx b/packages/vuetify/src/components/VCombobox/VCombobox.tsx index 65700c09132..0b0bc487d84 100644 --- a/packages/vuetify/src/components/VCombobox/VCombobox.tsx +++ b/packages/vuetify/src/components/VCombobox/VCombobox.tsx @@ -110,6 +110,7 @@ export const VCombobox = genericComponent true, 'update:search': (val: string) => true, 'update:menu': (val: boolean) => true, + 'change': (selected: any, added: any, removed: any) => true, }, setup (props, { emit, slots }) { @@ -182,11 +183,20 @@ export const VCombobox = genericComponent { - if (!props.multiple) { - _search.value = value[0]?.title ?? '' + + watch( + model, + (val, oldVal) => { + if (!props.multiple) { + _search.value = val[0]?.title ?? '' + } + emit('change', + model.value.map(v => v.props.value), + val.filter(v => !oldVal.includes(v)).map(v => v.props.value), + oldVal.filter(v => !val.includes(v)).map(v => v.props.value) + ) } - }) + ) const { filteredItems, getMatches } = useFilter(props, items, () => isPristine.value ? '' : search.value) diff --git a/packages/vuetify/src/components/VSelect/VSelect.tsx b/packages/vuetify/src/components/VSelect/VSelect.tsx index f51910c4c03..894fd59ff12 100644 --- a/packages/vuetify/src/components/VSelect/VSelect.tsx +++ b/packages/vuetify/src/components/VSelect/VSelect.tsx @@ -23,7 +23,7 @@ import { useProxiedModel } from '@/composables/proxiedModel' import { makeTransitionProps } from '@/composables/transition' // Utilities -import { computed, mergeProps, ref, shallowRef } from 'vue' +import { computed, mergeProps, ref, shallowRef, watch } from 'vue' import { deepEqual, genericComponent, getPropertyFromItem, matchesSelector, omit, propsFactory, useRender, wrapInArray } from '@/util' // Types @@ -121,9 +121,10 @@ export const VSelect = genericComponent true, 'update:modelValue': (val: any) => true, 'update:menu': (val: boolean) => true, + 'change': (selected: any, added: any, removed: any) => true, }, - setup (props, { slots }) { + setup (props, { emit, slots }) { const { t } = useLocale() const vTextFieldRef = ref() const vMenuRef = ref() @@ -182,6 +183,7 @@ export const VSelect = genericComponent() const { onListScroll, onListKeydown } = useScrolling(listRef, vTextFieldRef) + function onClear (e: MouseEvent) { if (props.openOnClear) { menu.value = true @@ -277,6 +279,17 @@ export const VSelect = genericComponent { + emit('change', + model.value.map(v => v.props.value), + val.filter(v => !oldVal.includes(v)).map(v => v.props.value), + oldVal.filter(v => !val.includes(v)).map(v => v.props.value) + ) + } + ) + useRender(() => { const hasChips = !!(props.chips || slots.chip) const hasList = !!(