Skip to content

Commit

Permalink
Merge pull request #1463 from privy-open-source/fix/asyncronous-selec…
Browse files Browse the repository at this point in the history
…t-option

fix(select): fix selected values when option items updated after search
  • Loading branch information
adenvt authored Sep 13, 2024
2 parents 01e47c7 + 3ea3e30 commit 567f59e
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 17 deletions.
39 changes: 38 additions & 1 deletion src/components/select/Select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ it('should have clear button if prop `clearable` was provided', async () => {

await fireEvent.click(clear)

expect(model.value).toBeUndefined()
expect(model.value).toStrictEqual({ text: '', value: undefined })
})

it('should clear search keyword if click clear button when select was opened', async () => {
Expand Down Expand Up @@ -595,3 +595,40 @@ it('should show selected items when options updated', async () => {

expect(activator).toHaveTextContent('orange')
})

it('should be keep selected when option changed after search', async () => {
const options = ref<string[]>([
'apple',
'grape',
'orange',
])
const model = ref('apple')
const screen = render({
components: { Select },
template : `
<Select
v-model="model"
:options="options"
/>
`,
setup () {
return { model, options }
},
})

const activator = screen.queryByTestId('select-activator')

expect(activator).toHaveTextContent('apple')

const select = screen.queryByTestId('select')
const caret = screen.queryByTestId('select-caret-icon')

await fireEvent.click(caret)

expect(select).toHaveClass('select--open')

await fireEvent.update(screen.queryByTestId('select-search'), 'orange')
await nextTick()

expect(activator).toHaveTextContent('apple')
})
36 changes: 21 additions & 15 deletions src/components/select/Select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ import { isEqual } from '../utils/value'
import { onStartTyping, watchPausable } from '@vueuse/core'
import type { SizeVariant } from '../button'
import type { MenuSizeVariant } from '../dropdown/'
import { isNil } from 'lodash-es'
import { isNil, uniqBy } from 'lodash-es'

defineOptions({
models: {
Expand Down Expand Up @@ -377,25 +377,28 @@ const modelWatcher = watchPausable(() => props.modelValue, (value) => {

watch(items, (options) => {
if (props.modelValue && options.length > 0) {
localModel.value = props.multiple
const value = props.multiple
? filterSelected(options, props.modelValue as unknown[])
: findSelected(options, props.modelValue)

localModel.value = props.multiple
? uniqBy([...localModel.value as SelectItem[], ...value as SelectItem[]], 'value')
: ((value as SelectItem).value === undefined ? localModel.value as SelectItem : value as SelectItem)
}
})

function setValue (item?: SelectItem) {
let value: SelectItem | SelectItem[]

if (props.multiple) {
if (item) {
if (Array.isArray(localModel.value)) {
value = localModel.value.some((val) => isEqual(val.value, item.value))
? localModel.value.filter((val) => !isEqual(val.value, item.value))
: [...localModel.value, item]
}
} else
value = []
} else
// define default item value
let value: SelectItem | SelectItem[] = props.multiple
? []
: { text: '', value: undefined }

if (props.multiple && item && Array.isArray(localModel.value)) {
value = localModel.value.some((val) => isEqual(val.value, item.value))
? localModel.value.filter((val) => !isEqual(val.value, item.value))
: [...localModel.value, item]
}
if (!props.multiple && item)
value = item

modelWatcher.pause()
Expand Down Expand Up @@ -431,7 +434,10 @@ function onClear () {
}

function isSelected (item: SelectItem) {
if (!localModel.value)
if (props.multiple && localModel.value.length === 0)
return false

if (!props.multiple && (localModel.value as SelectItem).value === undefined)
return false

if (props.multiple && Array.isArray(localModel.value))
Expand Down
20 changes: 19 additions & 1 deletion src/components/select/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ description: Base form input.
const province = ref('')
const city = ref('')
const multiValue = ref([])
const provinces = ref([])

const provincesAdapter = defineAsyncAdapter(async (keyword, page, perPage) => {
const response = await getProvinces(keyword, page, perPage)
Expand Down Expand Up @@ -258,6 +259,10 @@ You can set size of select via `size` prop. Available size are `lg`, `md`, `sm`,
<p-select :options="optionsD" v-model="multiValue" multiple />
</preview>

**Result :**

<pre><code>{{ multiValue || [] }}</code></pre>

```vue
<template>
<p-select :options="optionsD" v-model="multiValue" multiple />
Expand Down Expand Up @@ -360,11 +365,24 @@ It will take care of loading, inifinite load, and other stuff.

<pre><code>{{ province }}</code></pre>

### Multiple value
<preview>
<p-select
:adapter="provincesAdapter"
v-model="provinces"
multiple />
</preview>

**Result:**

<pre><code>{{ provinces }}</code></pre>

```vue
<template>
<p-select
:adapter="provincesAdapter"
v-model="province" />
v-model="province"
multiple />
</template>
<script setup>
Expand Down

0 comments on commit 567f59e

Please sign in to comment.