From 6f923bd327264eae043c28ad8c5c5d8faa32c0da Mon Sep 17 00:00:00 2001 From: Merlin Flach Date: Mon, 7 Nov 2022 16:19:29 +0100 Subject: [PATCH 1/8] fix: loadMore is only emitted once --- src/utils/useScroll.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils/useScroll.ts b/src/utils/useScroll.ts index 14f4e18..99f8a9a 100644 --- a/src/utils/useScroll.ts +++ b/src/utils/useScroll.ts @@ -1,6 +1,7 @@ import type {Ref, SetupContext} from 'vue' import {computed} from 'vue' import type {Option} from '../types' +import _ from "lodash"; export default function useScroll( infinite: Ref, @@ -12,11 +13,11 @@ export default function useScroll( return selectOptions.value.length < maxOptions.value }) - function handleScroll(e: Event) { + const handleScroll = _.debounce((e: Event) => { const {scrollTop, offsetHeight, scrollHeight} = e.target as HTMLDivElement if (scrollTop + offsetHeight >= scrollHeight && hasMore.value) context.emit('loadMore') - } + }, 50) return { hasMore, From ecde688bee275c967b23604414369e707018551a Mon Sep 17 00:00:00 2001 From: Merlin Flach Date: Mon, 7 Nov 2022 16:20:34 +0100 Subject: [PATCH 2/8] fix: multiselect isn't cleared if options are removed in infinite mode --- src/Multiselect.vue | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Multiselect.vue b/src/Multiselect.vue index 2d235ec..d3606b0 100644 --- a/src/Multiselect.vue +++ b/src/Multiselect.vue @@ -453,14 +453,16 @@ export default defineComponent({ ) watch(() => props.selectOptions, (newOptions, oldOptions) => { - if (newOptions && newOptions.length > 0) { - for (const option of oldOptions) { - if (!_.some(newOptions, option as never) && options.isSelected(option, options.selectedOptions.value)) - options.deselect(option) + if (!props.infinite) { + if (newOptions && newOptions.length > 0) { + for (const option of oldOptions) { + if (!_.some(newOptions, option as never) && options.isSelected(option, options.selectedOptions.value)) + options.deselect(option) + } + } + else { + multiselect.clear() } - } - else { - multiselect.clear() } }) From c199502c3ce7c4befc7c75ebbdd34fd0e3512966 Mon Sep 17 00:00:00 2001 From: Merlin Flach Date: Mon, 7 Nov 2022 17:25:44 +0100 Subject: [PATCH 3/8] fix: don't emit 'loadMore' if options are currently loading --- src/Multiselect.vue | 14 ++++++++------ src/utils/useScroll.ts | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Multiselect.vue b/src/Multiselect.vue index d3606b0..7617850 100644 --- a/src/Multiselect.vue +++ b/src/Multiselect.vue @@ -404,7 +404,7 @@ export default defineComponent({ setup(props, context: SetupContext) { const { multiple, modelValue, searchable, disabled, closeOnSelect, selectOptions, displaySelectedValues, - optionValue, optionLabel, optionDisabled, optionSearchValue, classes, infinite, maxOptions, + optionValue, optionLabel, optionDisabled, optionSearchValue, classes, infinite, maxOptions, loadingOptions, } = toRefs(props) const value = useValue(multiple, modelValue) const dropdown = useDropdown(context) @@ -439,6 +439,7 @@ export default defineComponent({ const scroll = useScroll( infinite, maxOptions, + loadingOptions, selectOptions, context, ) @@ -452,19 +453,20 @@ export default defineComponent({ multiselect.isActive, ) - watch(() => props.selectOptions, (newOptions, oldOptions) => { - if (!props.infinite) { + if (!props.infinite) { + watch(() => props.selectOptions, (newOptions, oldOptions) => { if (newOptions && newOptions.length > 0) { for (const option of oldOptions) { - if (!_.some(newOptions, option as never) && options.isSelected(option, options.selectedOptions.value)) + if (!_.some(newOptions, option as Option) && options.isSelected(option, options.selectedOptions.value)) options.deselect(option) } } else { multiselect.clear() } - } - }) + }) + } + return { ...value, diff --git a/src/utils/useScroll.ts b/src/utils/useScroll.ts index 99f8a9a..55ffd6a 100644 --- a/src/utils/useScroll.ts +++ b/src/utils/useScroll.ts @@ -6,6 +6,7 @@ import _ from "lodash"; export default function useScroll( infinite: Ref, maxOptions: Ref, + loadingOptions: Ref, selectOptions: Ref>, context: SetupContext, ) { @@ -15,7 +16,7 @@ export default function useScroll( const handleScroll = _.debounce((e: Event) => { const {scrollTop, offsetHeight, scrollHeight} = e.target as HTMLDivElement - if (scrollTop + offsetHeight >= scrollHeight && hasMore.value) + if (scrollTop + offsetHeight >= scrollHeight && hasMore.value && !loadingOptions.value) context.emit('loadMore') }, 50) From 318957cc155b1a20994c29588d811d5f5f0ebabf Mon Sep 17 00:00:00 2001 From: Merlin Flach Date: Tue, 15 Nov 2022 15:18:44 +0100 Subject: [PATCH 4/8] feat: performance rework --- src/Multiselect.vue | 77 ++++++--- src/stories/MultiselectTester.stories.js | 2 +- src/tests/MultiselectTester.vue | 21 ++- src/utils/index.ts | 1 - src/utils/useMultiselect.ts | 13 -- src/utils/useOptions.ts | 208 +++++++++++++++-------- src/utils/useSearch.ts | 26 +-- src/utils/useValue.ts | 24 --- 8 files changed, 220 insertions(+), 152 deletions(-) delete mode 100644 src/utils/useValue.ts diff --git a/src/Multiselect.vue b/src/Multiselect.vue index 7617850..649a01b 100644 --- a/src/Multiselect.vue +++ b/src/Multiselect.vue @@ -10,7 +10,7 @@ @mousedown.self="handleMousedown" >