Merge pull request 'feat(VnSelect): refs #7136 add scroll' (!890) from 7136-vnSelect_paginate_simplify_2 into dev
gitea/salix-front/pipeline/head This commit looks good Details

Reviewed-on: #890
Reviewed-by: Javier Segarra <jsegarra@verdnatura.es>
This commit is contained in:
Alex Moreno 2024-11-15 10:24:46 +00:00
commit e8f0bc9965
2 changed files with 36 additions and 20 deletions

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import { ref, toRefs, computed, watch, onMounted, useAttrs } from 'vue'; import { ref, toRefs, computed, watch, onMounted, useAttrs } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import FetchData from 'src/components/FetchData.vue'; import { useArrayData } from 'src/composables/useArrayData';
import { useRequired } from 'src/composables/useRequired'; import { useRequired } from 'src/composables/useRequired';
import dataByOrder from 'src/utils/dataByOrder'; import dataByOrder from 'src/utils/dataByOrder';
@ -90,6 +90,10 @@ const $props = defineProps({
type: Boolean, type: Boolean,
default: false, default: false,
}, },
dataKey: {
type: String,
default: null,
},
}); });
const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])]; const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])];
@ -98,14 +102,14 @@ const { optionLabel, optionValue, optionFilter, optionFilterValue, options, mode
const myOptions = ref([]); const myOptions = ref([]);
const myOptionsOriginal = ref([]); const myOptionsOriginal = ref([]);
const vnSelectRef = ref(); const vnSelectRef = ref();
const dataRef = ref();
const lastVal = ref(); const lastVal = ref();
const noOneText = t('globals.noOne'); const noOneText = t('globals.noOne');
const noOneOpt = ref({ const noOneOpt = ref({
[optionValue.value]: false, [optionValue.value]: false,
[optionLabel.value]: noOneText, [optionLabel.value]: noOneText,
}); });
const isLoading = ref(false);
const useURL = computed(() => $props.url);
const value = computed({ const value = computed({
get() { get() {
return $props.modelValue; return $props.modelValue;
@ -129,11 +133,18 @@ watch(modelValue, async (newValue) => {
onMounted(() => { onMounted(() => {
setOptions(options.value); setOptions(options.value);
if ($props.url && $props.modelValue && !findKeyInOptions()) if (useURL.value && $props.modelValue && !findKeyInOptions())
fetchFilter($props.modelValue); fetchFilter($props.modelValue);
if ($props.focusOnMount) setTimeout(() => vnSelectRef.value.showPopup(), 300); if ($props.focusOnMount) setTimeout(() => vnSelectRef.value.showPopup(), 300);
}); });
defineExpose({ opts: myOptions });
const arrayDataKey =
$props.dataKey ?? ($props.url?.length > 0 ? $props.url : $attrs.name ?? $attrs.label);
const arrayData = useArrayData(arrayDataKey, { url: $props.url, searchUrl: false });
function findKeyInOptions() { function findKeyInOptions() {
if (!$props.options) return; if (!$props.options) return;
return filter($props.modelValue, $props.options)?.length; return filter($props.modelValue, $props.options)?.length;
@ -168,7 +179,7 @@ function filter(val, options) {
} }
async function fetchFilter(val) { async function fetchFilter(val) {
if (!$props.url || !dataRef.value) return; if (!$props.url) return;
const { fields, include, sortBy, limit } = $props; const { fields, include, sortBy, limit } = $props;
const key = const key =
@ -190,8 +201,8 @@ async function fetchFilter(val) {
const fetchOptions = { where, include, limit }; const fetchOptions = { where, include, limit };
if (fields) fetchOptions.fields = fields; if (fields) fetchOptions.fields = fields;
if (sortBy) fetchOptions.order = sortBy; if (sortBy) fetchOptions.order = sortBy;
arrayData.reset(['skip', 'filter.skip', 'page']);
return dataRef.value.fetch(fetchOptions); return (await arrayData.applyFilter({ filter: fetchOptions }))?.data;
} }
async function filterHandler(val, update) { async function filterHandler(val, update) {
@ -231,20 +242,23 @@ function nullishToTrue(value) {
const getVal = (val) => ($props.useLike ? { like: `%${val}%` } : val); const getVal = (val) => ($props.useLike ? { like: `%${val}%` } : val);
defineExpose({ opts: myOptions }); async function onScroll({ to, direction, from, index }) {
const lastIndex = myOptions.value.length - 1;
if (from === 0 && index === 0) return;
if (!useURL.value && !$props.fetchRef) return;
if (direction === 'decrease') return;
if (to === lastIndex && arrayData.store.hasMoreData && !isLoading.value) {
isLoading.value = true;
await arrayData.loadMore();
setOptions(arrayData.store.data);
vnSelectRef.value.scrollTo(lastIndex);
isLoading.value = false;
}
}
</script> </script>
<template> <template>
<FetchData
ref="dataRef"
:url="$props.url"
@on-fetch="(data) => setOptions(data)"
:where="where || { [optionValue]: value }"
:limit="limit"
:sort-by="sortBy"
:fields="fields"
:params="params"
/>
<QSelect <QSelect
v-model="value" v-model="value"
:options="myOptions" :options="myOptions"
@ -263,6 +277,9 @@ defineExpose({ opts: myOptions });
:rules="mixinRules" :rules="mixinRules"
virtual-scroll-slice-size="options.length" virtual-scroll-slice-size="options.length"
hide-bottom-space hide-bottom-space
:input-debounce="useURL ? '300' : '0'"
:loading="isLoading"
@virtual-scroll="onScroll"
> >
<template v-if="isClearable" #append> <template v-if="isClearable" #append>
<QIcon <QIcon

View File

@ -53,7 +53,7 @@ defineProps({
<QItemSection> <QItemSection>
<VnSelect <VnSelect
url="Workers/activeWithInheritedRole" url="Workers/activeWithInheritedRole"
:filter="{ where: { role: 'salesPerson' } }" :where="{ role: 'salesPerson' }"
auto-load auto-load
:label="t('Salesperson')" :label="t('Salesperson')"
v-model="params.salesPersonFk" v-model="params.salesPersonFk"
@ -67,7 +67,6 @@ defineProps({
dense dense
outlined outlined
rounded rounded
:input-debounce="0"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>