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

fix(SelectMenu): use by prop to compare objects for selected values #2228

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions src/runtime/components/forms/SelectMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -365,14 +365,35 @@ export default defineComponent({

const selected = computed(() => {
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]))
if (props.by) {
// handle the case when the valueAttribute is an object, and we need to compare by a specific key
return options.value.filter(
option => typeof option === 'object' && option !== null
&& typeof option[props.valueAttribute] === 'object' && option[props.valueAttribute] !== null && modelValue.some(
(value: any) => typeof value === 'object' && value !== null && value[props.by] === option[props.valueAttribute][props.by]
)
)
}

// compute selected items by the valueAttribute form the options
return options.value.filter(option => modelValue.includes(option[props.valueAttribute]))
}
return options.value.filter(option => (props.modelValue as any[]).includes(option))

if (props.by) {
return options.value.filter(
option => typeof option === 'object' && option !== null && modelValue.some(
(value: any) => typeof value === 'object' && value !== null && value[props.by] === option[props.by]
)
)
}

return options.value.filter(option => modelValue.includes(option))
}

if (props.valueAttribute) {
Expand Down Expand Up @@ -481,7 +502,7 @@ export default defineComponent({
}

return props.options || []
}, [], {
}, props.options || [], {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benjamincanac Since the selected computed proeprty uses the computedAsync optionsΒ to get the possible values, I initialized it to props.optionsΒ so that it isn't empty during the initial render of the component to prevent a flash.
However, now that I'm thinking about it, shouldn't we just use props.options directly in the selectedΒ computed, instead of options - since we don't want to compare the model values with only the search results, but rather the whole options?

Copy link
Contributor Author

@CernyMatej CernyMatej Sep 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used options because that's what was used previously, however, unless I'm missing something, I think that props.options should have been used there as well:

image

Though this only affects things if someone uses asynchronous search.

lazy: props.searchableLazy
})

Expand Down