feat(components): [autocomplete] fetchSuggestions supports Promise (#6695)

This commit is contained in:
Carter Li 2022-03-21 15:51:39 +08:00 committed by GitHub
parent 03f28a7a1a
commit bdbb70b49c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 16 deletions

View File

@ -8,7 +8,10 @@ jest.unmock('lodash')
jest.useFakeTimers()
const _mount = (payload = {}) =>
const _mount = (
payload = {},
type: 'fn-cb' | 'fn-promise' | 'fn-arr' | 'arr' = 'fn-cb'
) =>
mount({
setup() {
const state = reactive({
@ -22,19 +25,33 @@ const _mount = (payload = {}) =>
payload,
})
const querySearch = (
queryString: string,
cb: (arg: typeof state.list) => void
) => {
cb(
queryString
? state.list.filter(
(i) => i.value.indexOf(queryString.toLowerCase()) === 0
)
: state.list
)
function filterList(queryString: string) {
return queryString
? state.list.filter(
(i) => i.value.indexOf(queryString.toLowerCase()) === 0
)
: state.list
}
const querySearch = (() => {
switch (type) {
case 'fn-cb':
return (
queryString: string,
cb: (arg: typeof state.list) => void
) => {
cb(filterList(queryString))
}
case 'fn-promise':
return (queryString: string) =>
Promise.resolve(filterList(queryString))
case 'fn-arr':
return (queryString: string) => filterList(queryString)
case 'arr':
return state.list
}
})()
return () => (
<Autocomplete
ref="autocomplete"
@ -134,6 +151,48 @@ describe('Autocomplete.vue', () => {
expect(fetchSuggestions).toHaveBeenCalledTimes(2)
})
test('fetchSuggestions with fn-promise', async () => {
const wrapper = _mount({ debounce: 10 }, 'fn-promise')
await nextTick()
await wrapper.find('input').trigger('focus')
jest.runAllTimers()
await nextTick()
const target = wrapper.getComponent(Autocomplete).vm as InstanceType<
typeof Autocomplete
>
expect(target.suggestions.length).toBe(4)
})
test('fetchSuggestions with fn-arr', async () => {
const wrapper = _mount({ debounce: 10 }, 'fn-arr')
await nextTick()
await wrapper.find('input').trigger('focus')
jest.runAllTimers()
await nextTick()
const target = wrapper.getComponent(Autocomplete).vm as InstanceType<
typeof Autocomplete
>
expect(target.suggestions.length).toBe(4)
})
test('fetchSuggestions with arr', async () => {
const wrapper = _mount({ debounce: 10 }, 'arr')
await nextTick()
await wrapper.find('input').trigger('focus')
jest.runAllTimers()
await nextTick()
const target = wrapper.getComponent(Autocomplete).vm as InstanceType<
typeof Autocomplete
>
expect(target.suggestions.length).toBe(4)
})
test('valueKey / modelValue', async () => {
const wrapper = _mount()
await nextTick()

View File

@ -38,8 +38,12 @@ export const autocompleteProps = buildProps({
},
fetchSuggestions: {
type: definePropType<
(queryString: string, cb: (data: any[]) => void) => void
>(Function),
| ((
queryString: string,
cb: (data: { value: string }[]) => void
) => { value: string }[] | Promise<{ value: string }[]> | void)
| { value: string }[]
>([Function, Array]),
default: NOOP,
},
popperClass: {

View File

@ -96,6 +96,7 @@ import {
nextTick,
useAttrs as useCompAttrs,
} from 'vue'
import { isPromise } from '@vue/shared'
import { debounce } from 'lodash-unified'
import { onClickOutside } from '@vueuse/core'
import { useAttrs, useNamespace } from '@element-plus/hooks'
@ -165,7 +166,7 @@ const getData = (queryString: string) => {
return
}
loading.value = true
props.fetchSuggestions(queryString, (suggestionsArg) => {
const cb = (suggestionsArg: any[]) => {
loading.value = false
if (suggestionDisabled.value) {
return
@ -176,7 +177,17 @@ const getData = (queryString: string) => {
} else {
throwError(COMPONENT_NAME, 'autocomplete suggestions must be an array')
}
})
}
if (isArray(props.fetchSuggestions)) {
cb(props.fetchSuggestions)
} else {
const result = props.fetchSuggestions(queryString, cb)
if (isArray(result)) {
cb(result)
} else if (isPromise(result)) {
result.then(cb)
}
}
}
const debouncedGetData = debounce(getData, props.debounce)
const handleInput = (value: string) => {