Enhance FormSelect component by adding search prompt for large lists and implementing debounced search functionality. Introduce new props for search configuration, improving user experience and performance during data selection.

This commit is contained in:
burakovec
2026-03-31 09:46:24 +03:00
parent a10f6997eb
commit 5557ecf52b

View File

@ -59,6 +59,12 @@
<span>Sonuç Bulunamadı</span>
</div>
<template v-else>
<div class="form-select-list-item" v-if="showSearchPrompt">
<span>
İlk {{ selectList.length }} kayıt gösteriliyor. Daha fazla sonuç için en az
{{ props.minSearchLength }} harf yazın.
</span>
</div>
<div
class="form-select-list-item"
v-if="multiple"
@ -104,7 +110,7 @@
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue'
import { useGlobalStore } from '@/stores/globalStore'
const globalStore = useGlobalStore()
@ -129,6 +135,10 @@
multipleText?: string
view?: Function
disabledClass?: string
largeListThreshold?: number
initialDisplayLimit?: number
minSearchLength?: number
searchDebounceMs?: number
}
const props = withDefaults(defineProps<Props>(), {
@ -139,7 +149,11 @@
clearable: false,
extraData: '',
multiple: false,
multipleText: 'Tümü'
multipleText: 'Tümü',
largeListThreshold: 100,
initialDisplayLimit: 100,
minSearchLength: 2,
searchDebounceMs: 120
})
const emit = defineEmits(['update:modelValue', 'change', 'clear'])
@ -147,9 +161,11 @@
const activated = ref<Boolean>(false)
const multipleAllSelected = ref<boolean>(false)
const q = ref<string>('')
const debouncedQuery = ref<string>('')
const rnd = ref<number>(Number(Math.floor(Math.random() * 1000000000)))
const localValue = ref<string | number | boolean | null | string[]>()
const selectedOption = ref<Record<string, any>>({})
let searchDebounceTimer: ReturnType<typeof setTimeout> | undefined
if (props.multiple) {
if (props.modelValue === null || props.modelValue === undefined) {
@ -225,12 +241,24 @@
}
})
const isLargeList = computed<boolean>(() => {
return props.listData.length > props.largeListThreshold
})
const showSearchPrompt = computed<boolean>(() => {
return isLargeList.value && debouncedQuery.value.length < props.minSearchLength
})
const selectList = computed<Record<string, any>[]>(() => {
if (q.value.length > 1) {
if (debouncedQuery.value.length >= props.minSearchLength) {
return props.listData.filter((v: Record<string, any>) => {
let val = props.listText !== undefined ? v[props.listText] : v
return globalStore.trToUpper(val).includes(globalStore.trToUpper(q.value))
return globalStore
.trToUpper(String(val))
.includes(globalStore.trToUpper(debouncedQuery.value))
})
} else if (isLargeList.value) {
return props.listData.slice(0, props.initialDisplayLimit)
} else {
return props.listData
}
@ -308,6 +336,7 @@
if (props.disabled) return
e.stopPropagation()
q.value = ''
debouncedQuery.value = ''
activated.value = true
setTimeout(() => {
@ -368,6 +397,18 @@
SetSelectedOption()
})
onUnmounted(() => {
if (searchDebounceTimer !== undefined) clearTimeout(searchDebounceTimer)
document.removeEventListener('click', closeList)
})
watch(q, (value: string) => {
if (searchDebounceTimer !== undefined) clearTimeout(searchDebounceTimer)
searchDebounceTimer = setTimeout(() => {
debouncedQuery.value = value.trim()
}, props.searchDebounceMs)
})
watch(
() => props.invalidText,
() => {