mirror of
https://github.com/element-plus/element-plus.git
synced 2024-11-21 01:02:59 +08:00
fix(components): [select] backspace delete disabled option (#11995)
* fix(components): [select] backspace delete disabled option * fix(components): [select] findLastIndex * fix(components): [select] simple polyfill findLastIndex in test file * fix(components): [select] add test for backspace * chore: lint
This commit is contained in:
parent
5c1306127f
commit
067028ba3c
@ -1914,10 +1914,10 @@ describe('Select', () => {
|
||||
await nextTick()
|
||||
|
||||
expect(innerInputEl.placeholder).toBe('')
|
||||
|
||||
selectInput.trigger('keydown', {
|
||||
key: EVENT_CODE.backspace,
|
||||
})
|
||||
|
||||
await nextTick()
|
||||
expect(innerInputEl.placeholder).toBe(placeholder)
|
||||
vi.useRealTimers()
|
||||
@ -2297,5 +2297,67 @@ describe('Select', () => {
|
||||
expect(vm.value).toBe(2)
|
||||
expect(findInnerInput().value).toBe('z')
|
||||
})
|
||||
// fix: https://github.com/element-plus/element-plus/issues/11991
|
||||
it('backspace key should not delete disabled options', async () => {
|
||||
const options = [
|
||||
{
|
||||
value: 'Option1',
|
||||
label: 'Option1',
|
||||
disable: true,
|
||||
},
|
||||
{
|
||||
value: 'Option2',
|
||||
label: 'Option2',
|
||||
disable: false,
|
||||
},
|
||||
]
|
||||
const value = ['Option2', 'Option1']
|
||||
const wrapper = _mount(
|
||||
`
|
||||
<el-select v-model="value"
|
||||
multiple
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
:label="option.label"
|
||||
:disabled="option.disable"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
`,
|
||||
() => ({
|
||||
value,
|
||||
options,
|
||||
})
|
||||
)
|
||||
await nextTick()
|
||||
const selectInput = wrapper.find('.el-select__input')
|
||||
expect(wrapper.findAll('.el-tag').length).toBe(2)
|
||||
// need trigger keydown twice because first keydown just select option, and second keydown is to delete
|
||||
await selectInput.trigger('keydown', {
|
||||
code: EVENT_CODE.backspace,
|
||||
key: EVENT_CODE.backspace,
|
||||
})
|
||||
await selectInput.trigger('keydown', {
|
||||
code: EVENT_CODE.backspace,
|
||||
key: EVENT_CODE.backspace,
|
||||
})
|
||||
await nextTick()
|
||||
expect(wrapper.findAll('.el-tag').length).toBe(1)
|
||||
await selectInput.trigger('keydown', {
|
||||
code: EVENT_CODE.backspace,
|
||||
key: EVENT_CODE.backspace,
|
||||
})
|
||||
await selectInput.trigger('keydown', {
|
||||
code: EVENT_CODE.backspace,
|
||||
key: EVENT_CODE.backspace,
|
||||
})
|
||||
await nextTick()
|
||||
// after the second deletion, an el-tag still exist
|
||||
expect(wrapper.findAll('.el-tag').length).toBe(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -11,7 +11,12 @@ import {
|
||||
watch,
|
||||
} from 'vue'
|
||||
import { isObject, toRawType } from '@vue/shared'
|
||||
import { get, isEqual, debounce as lodashDebounce } from 'lodash-unified'
|
||||
import {
|
||||
findLastIndex,
|
||||
get,
|
||||
isEqual,
|
||||
debounce as lodashDebounce,
|
||||
} from 'lodash-unified'
|
||||
import {
|
||||
CHANGE_EVENT,
|
||||
EVENT_CODE,
|
||||
@ -40,6 +45,7 @@ export function useSelectStates(props) {
|
||||
return reactive({
|
||||
options: new Map(),
|
||||
cachedOptions: new Map(),
|
||||
disabledOptions: new Map(),
|
||||
createdLabel: null,
|
||||
createdSelected: false,
|
||||
selected: props.multiple ? [] : ({} as any),
|
||||
@ -627,11 +633,16 @@ export const useSelect = (props, states: States, ctx) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getLastNotDisabledIndex = (value) =>
|
||||
findLastIndex(value, (it) => !states.disabledOptions.has(it))
|
||||
|
||||
const deletePrevTag = (e) => {
|
||||
if (e.code === EVENT_CODE.delete) return
|
||||
if (e.target.value.length <= 0 && !toggleLastOptionHitState()) {
|
||||
const value = props.modelValue.slice()
|
||||
value.pop()
|
||||
const lastNotDisabledIndex = getLastNotDisabledIndex(value)
|
||||
if (lastNotDisabledIndex < 0) return
|
||||
value.splice(lastNotDisabledIndex, 1)
|
||||
ctx.emit(UPDATE_MODEL_EVENT, value)
|
||||
emitChange(value)
|
||||
}
|
||||
@ -754,6 +765,7 @@ export const useSelect = (props, states: States, ctx) => {
|
||||
states.filteredOptionsCount++
|
||||
states.options.set(vm.value, vm)
|
||||
states.cachedOptions.set(vm.value, vm)
|
||||
vm.disabled && states.disabledOptions.set(vm.value, vm)
|
||||
}
|
||||
|
||||
const onOptionDestroy = (key, vm: SelectOptionProxy) => {
|
||||
@ -772,7 +784,10 @@ export const useSelect = (props, states: States, ctx) => {
|
||||
|
||||
const toggleLastOptionHitState = (hit?: boolean) => {
|
||||
if (!Array.isArray(states.selected)) return
|
||||
const option = states.selected[states.selected.length - 1]
|
||||
const lastNotDisabledIndex = getLastNotDisabledIndex(
|
||||
states.selected.map((it) => it.value)
|
||||
)
|
||||
const option = states.selected[lastNotDisabledIndex]
|
||||
if (!option) return
|
||||
|
||||
if (hit === true || hit === false) {
|
||||
|
Loading…
Reference in New Issue
Block a user