From c8d0a30fcbcebe66ba16c7e442732b977737af41 Mon Sep 17 00:00:00 2001
From: Oleg <64714442+aluarius@users.noreply.github.com>
Date: Tue, 31 Jan 2023 15:19:19 +0400
Subject: [PATCH] [#2785] Throttling composable, integration to VaSelect and
VaDataTable (#2832)
---
packages/docs/src/locales/en/en.json | 1 +
packages/docs/src/locales/ru/ru.json | 1 +
packages/docs/src/locales/zh-cn/zh-cn.json | 4 +-
.../va-data-table/VaDataTable.new.demo.vue | 13 +++
.../components/va-data-table/VaDataTable.vue | 3 +-
.../va-data-table/hooks/useFilterable.ts | 13 ++-
.../va-data-table/hooks/usePaginatedRows.ts | 7 +-
.../va-data-table/hooks/useSortable.ts | 7 +-
.../components/va-select/VaSelect.demo.vue | 7 ++
.../ui/src/components/va-select/VaSelect.vue | 4 +-
.../VaSelectOptionList/VaSelectOptionList.vue | 7 +-
packages/ui/src/composables/index.ts | 1 +
packages/ui/src/composables/useThrottle.ts | 101 ++++++++++++++++++
13 files changed, 158 insertions(+), 11 deletions(-)
create mode 100644 packages/ui/src/composables/useThrottle.ts
diff --git a/packages/docs/src/locales/en/en.json b/packages/docs/src/locales/en/en.json
index 633660584b..a5ed2af944 100644
--- a/packages/docs/src/locales/en/en.json
+++ b/packages/docs/src/locales/en/en.json
@@ -186,6 +186,7 @@
"fallbackText": "Shows an alternative text if image failed to load or src doesn't specified.",
"fallbackIcon": "Shows an icon if image failed to load or src doesn't specified.",
"fallbackRender": "Allows to use render function to render custom contents if image failed to load or src doesn't specified",
+ "delay": "Sets throttling delay (ms) for the components any data change (useful for huge data).",
"ratio": "Aspect ratio of the component's wrapper."
}
},
diff --git a/packages/docs/src/locales/ru/ru.json b/packages/docs/src/locales/ru/ru.json
index 907d495542..c33cf6e834 100644
--- a/packages/docs/src/locales/ru/ru.json
+++ b/packages/docs/src/locales/ru/ru.json
@@ -183,6 +183,7 @@
"fallbackText": "Показывает альтернативный текст, если изображение не указано или не удалось загрузить.",
"fallbackIcon": "Показывает альтернативную иконку, если изображение не указано или не удалось загрузить.",
"fallbackRender": "Позволяет задать функцию-рендерер с настраиваемым содержимым, если изображение не указано или не удалось загрузить.",
+ "delay": "Устанавливает задержку (тротлинг в ms) изменения данных в компоненте (при рендеринге больших объемов данных).",
"ratio": "Соотношение сторон обертки компонента."
}
},
diff --git a/packages/docs/src/locales/zh-cn/zh-cn.json b/packages/docs/src/locales/zh-cn/zh-cn.json
index 239edf24cb..66aa1a76a4 100644
--- a/packages/docs/src/locales/zh-cn/zh-cn.json
+++ b/packages/docs/src/locales/zh-cn/zh-cn.json
@@ -179,10 +179,12 @@
"plain": "Applies `plain` styling.",
"round": "Adds rounded corners (or make a button fully rounded if only icon is passed).",
"iconRight": "The icon to be displayed to the right of a title.",
+ "keyboardNavigation": "Enables keyboard navigation for the component.",
"fallbackSrc": "Shows an alternative image if original image failed to load or src doesn't specified.",
"fallbackText": "Shows an alternative text if image failed to load or src doesn't specified.",
"fallbackIcon": "Shows an icon if image failed to load or src doesn't specified.",
- "fallbackRender": "Allows to use render function to render custom contents if image failed to load or src doesn't specified"
+ "fallbackRender": "Allows to use render function to render custom contents if image failed to load or src doesn't specified",
+ "delay": "Sets throttling delay (ms) for the components any data change (useful for huge data)."
}
},
"VaBadge": {
diff --git a/packages/ui/src/components/va-data-table/VaDataTable.new.demo.vue b/packages/ui/src/components/va-data-table/VaDataTable.new.demo.vue
index cc7acc6db6..f3f6f713e2 100644
--- a/packages/ui/src/components/va-data-table/VaDataTable.new.demo.vue
+++ b/packages/ui/src/components/va-data-table/VaDataTable.new.demo.vue
@@ -120,6 +120,19 @@
+
+
+ {{ label }}
+ Company Name
+
+
+
,
@@ -553,7 +555,7 @@ export default defineComponent({
}))
const optionsListPropsComputed = computed(() => ({
- ...pick(props, ['textBy', 'trackBy', 'groupBy', 'disabledBy', 'color', 'virtualScroller']),
+ ...pick(props, ['textBy', 'trackBy', 'groupBy', 'disabledBy', 'color', 'virtualScroller', 'delay']),
search: searchInput.value,
tabindex: tabIndexComputed.value,
selectedValue: valueComputed.value,
diff --git a/packages/ui/src/components/va-select/components/VaSelectOptionList/VaSelectOptionList.vue b/packages/ui/src/components/va-select/components/VaSelectOptionList/VaSelectOptionList.vue
index a170914326..b11a832c14 100644
--- a/packages/ui/src/components/va-select/components/VaSelectOptionList/VaSelectOptionList.vue
+++ b/packages/ui/src/components/va-select/components/VaSelectOptionList/VaSelectOptionList.vue
@@ -80,6 +80,7 @@ import {
useObjectRefs,
useSlotPassed,
useSelectableList, useSelectableListProps,
+ useThrottleValue, useThrottleProps,
} from '../../../../composables'
import { scrollToElement } from '../../../../utils/scroll-to-element'
@@ -102,6 +103,7 @@ export default defineComponent({
...useColorProps,
...useComponentPresetProp,
...useSelectableListProps,
+ ...useThrottleProps,
noOptionsText: { type: String, default: 'Items not found' },
getSelectedState: { type: Function as PropType<(option: SelectOption) => boolean>, required: true },
multiple: { type: Boolean, default: false },
@@ -162,6 +164,7 @@ export default defineComponent({
return groups
}, { _noGroup: [] }))
+ const optionGroupsThrottled = useThrottleValue(optionGroups, props)
const isValueExists = (value: SelectOption | null | undefined) => !!value || value === 0
@@ -174,7 +177,7 @@ export default defineComponent({
const selectOption = (option: SelectOption) => !getDisabled(option) && emit('select-option', option)
- const groupedOptions = computed(() => Object.values(optionGroups.value).flat())
+ const groupedOptions = computed(() => Object.values(optionGroupsThrottled.value).flat())
const currentOptions = computed(() =>
filteredOptions.value.some((el) => getGroupBy(el)) ? groupedOptions.value : filteredOptions.value)
@@ -259,7 +262,7 @@ export default defineComponent({
virtualScrollerRef,
rootHeight,
- optionGroups,
+ optionGroups: optionGroupsThrottled,
filteredOptions,
selectOptionProps,
isSlotContentPassed,
diff --git a/packages/ui/src/composables/index.ts b/packages/ui/src/composables/index.ts
index 8b2737bf83..45ed5db520 100644
--- a/packages/ui/src/composables/index.ts
+++ b/packages/ui/src/composables/index.ts
@@ -58,6 +58,7 @@ export * from './useTimer'
export * from './useTrackBy'
export * from './useTranslation'
export * from './useTrapFocus'
+export * from './useThrottle'
export * from './useValidation'
export * from './useWindow'
export * from './useWindowSize'
diff --git a/packages/ui/src/composables/useThrottle.ts b/packages/ui/src/composables/useThrottle.ts
new file mode 100644
index 0000000000..8f117387bd
--- /dev/null
+++ b/packages/ui/src/composables/useThrottle.ts
@@ -0,0 +1,101 @@
+/**
+ * @description returns throttled function or value
+ * the last one always returns last-call value in the end if no more new calls were provided
+ * @example
+ * import { useThrottleFunction, useThrottleValue } from '../../composables'
+ * ...
+ * const localThrottledFunction = useThrottleFunction(functionToThrottle, props)
+ * const localThrottledValue = useThrottleValue(reactiveValueToThrottle, props)
+ */
+
+import {
+ ref, toRef, unref,
+ watch,
+ Ref, ExtractPropTypes, ComponentInternalInstance,
+} from 'vue'
+
+type ThrottledFunctionArgs = any[]
+type ThrottledFunction