diff --git a/src/runtime/components/forms/InputMenu.vue b/src/runtime/components/forms/InputMenu.vue index 5ce1e764..2264b503 100644 --- a/src/runtime/components/forms/InputMenu.vue +++ b/src/runtime/components/forms/InputMenu.vue @@ -48,7 +48,7 @@ v-slot="{ active, selected, disabled: optionDisabled }" :key="index" as="template" - :value="valueAttribute ? option[valueAttribute] : option" + :value="valueAttribute ? accessor(option, valueAttribute) : option" :disabled="option.disabled" >
  • @@ -104,6 +104,7 @@ import { import { computedAsync, useDebounceFn } from '@vueuse/core' import { defu } from 'defu' import { twMerge, twJoin } from 'tailwind-merge' +import { isEqual } from 'ohash' import UIcon from '../elements/Icon.vue' import UAvatar from '../elements/Avatar.vue' import { useUI } from '../../composables/useUI' @@ -308,8 +309,28 @@ export default defineComponent({ return } + function getValue(value: any) { + if (props.valueAttribute) { + return accessor(value, props.valueAttribute) + } + + return value + } + + function compareValues(value1: any, value2: any) { + if (props.by && typeof value1 === 'object' && typeof value2 === 'object') { + return isEqual(value1[props.by], value2[props.by]) + } + return isEqual(value1, value2) + } + if (props.valueAttribute) { - const option = options.value.find(option => option[props.valueAttribute] === props.modelValue) + const option = options.value.find((option) => { + const optionValue = getValue(option) + + return compareValues(optionValue, props.modelValue) + }) + return option ? accessor(option, props.optionAttribute) : null } else { return ['string', 'number'].includes(typeof props.modelValue) ? props.modelValue : accessor(props.modelValue as Record, props.optionAttribute) diff --git a/src/runtime/components/forms/SelectMenu.vue b/src/runtime/components/forms/SelectMenu.vue index 273f1bd7..eac8cbc3 100644 --- a/src/runtime/components/forms/SelectMenu.vue +++ b/src/runtime/components/forms/SelectMenu.vue @@ -71,7 +71,7 @@ v-slot="{ active, selected: optionSelected, disabled: optionDisabled }" :key="index" as="template" - :value="valueAttribute ? option[valueAttribute] : option" + :value="valueAttribute ? accessor(option, valueAttribute) : option" :disabled="option.disabled" >
  • @@ -140,6 +140,7 @@ import { import { computedAsync, useDebounceFn } from '@vueuse/core' import { defu } from 'defu' import { twMerge, twJoin } from 'tailwind-merge' +import { isEqual } from 'ohash' import UIcon from '../elements/Icon.vue' import UAvatar from '../elements/Avatar.vue' import { useUI } from '../../composables/useUI' @@ -364,39 +365,53 @@ export default defineComponent({ }) const selected = computed(() => { + function compareValues(value1: any, value2: any) { + if (props.by && typeof value1 === 'object' && typeof value2 === 'object') { + return isEqual(value1[props.by], value2[props.by]) + } + return isEqual(value1, value2) + } + + function getValue(value: any) { + if (props.valueAttribute) { + return accessor(value, props.valueAttribute) + } + + return value + } + if (props.multiple) { - if (!Array.isArray(props.modelValue) || !props.modelValue.length) { + const modelValue = props.modelValue + if (!Array.isArray(modelValue) || !modelValue.length) { return [] } - if (props.valueAttribute) { - return options.value.filter(option => (props.modelValue as any[]).includes(option[props.valueAttribute])) - } - return options.value.filter(option => (props.modelValue as any[]).includes(option)) + return options.value.filter((option) => { + const optionValue = getValue(option) + return modelValue.some(value => compareValues(value, optionValue)) + }) } - if (props.valueAttribute) { - return options.value.find(option => option[props.valueAttribute] === props.modelValue) - } - return options.value.find(option => option === props.modelValue) + return options.value.find((option) => { + const optionValue = getValue(option) + return compareValues(optionValue, toRaw(props.modelValue)) + }) ?? props.modelValue }) const label = computed(() => { - if (props.multiple) { - if (Array.isArray(props.modelValue) && props.modelValue.length) { - return `${selected.value.length} selected` - } else { - return null - } - } else if (props.modelValue !== undefined && props.modelValue !== null) { - if (props.valueAttribute) { - return accessor(selected.value, props.optionAttribute) ?? null - } else { - return ['string', 'number'].includes(typeof props.modelValue) ? props.modelValue : accessor(props.modelValue as Record, props.optionAttribute) - } + if (!selected.value) return null + + if (props.valueAttribute) { + return accessor(selected.value as Record, props.optionAttribute) } - return null + if (Array.isArray(props.modelValue) && props.modelValue.length) { + return `${props.modelValue.length} selected` + } else if (['string', 'number'].includes(typeof props.modelValue)) { + return props.modelValue + } + + return accessor(props.modelValue as Record, props.optionAttribute) }) const selectClass = computed(() => {