diff --git a/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx b/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx index 663807878df..9d210e1ccc9 100644 --- a/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx +++ b/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx @@ -119,9 +119,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) @@ -376,6 +377,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 ff3f5e5a261..448bdc22526 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 }) { @@ -183,11 +184,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 4e90caf4215..5a47e29ca48 100644 --- a/packages/vuetify/src/components/VSelect/VSelect.tsx +++ b/packages/vuetify/src/components/VSelect/VSelect.tsx @@ -131,9 +131,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() @@ -193,6 +194,7 @@ export const VSelect = genericComponent() const { onListScroll, onListKeydown } = useScrolling(listRef, vTextFieldRef) + function onClear (e: MouseEvent) { if (props.openOnClear) { menu.value = true @@ -287,7 +289,7 @@ export const VSelect = genericComponent { if (!props.hideSelected && menu.value && selections.value.length) { const index = displayItems.value.findIndex( @@ -299,6 +301,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 = !!(