|
27 | 27 | multiple |
28 | 28 | class="w-full" |
29 | 29 | :options="columnOptions[c.name] || []" |
30 | | - @update:modelValue="setFilterItem({ column: c, operator: 'in', value: $event.length ? $event : undefined })" |
| 30 | + @update:modelValue="onFilterInput[c.name]({ column: c, operator: 'in', value: $event.length ? $event : undefined })" |
31 | 31 | :modelValue="filtersStore.filters.find(f => f.field === c.name && f.operator === 'in')?.value || []" |
32 | 32 | /> |
33 | 33 | <Select |
|
40 | 40 | // if field is not required, undefined might be there, and user might want to filter by it |
41 | 41 | ...(c.required ? [] : [ { label: $t('Unset'), value: undefined } ]) |
42 | 42 | ]" |
43 | | - @update:modelValue="setFilterItem({ column: c, operator: 'in', value: $event.length ? $event : undefined })" |
| 43 | + @update:modelValue="onFilterInput[c.name]({ column: c, operator: 'in', value: $event.length ? $event : undefined })" |
44 | 44 | :modelValue="filtersStore.filters.find(f => f.field === c.name && f.operator === 'in')?.value || []" |
45 | 45 | /> |
46 | 46 |
|
|
49 | 49 | class="w-full" |
50 | 50 | v-else-if="c.enum" |
51 | 51 | :options="c.enum" |
52 | | - @update:modelValue="setFilterItem({ column: c, operator: 'in', value: $event.length ? $event : undefined })" |
| 52 | + @update:modelValue="onFilterInput[c.name]({ column: c, operator: 'in', value: $event.length ? $event : undefined })" |
53 | 53 | :modelValue="filtersStore.filters.find(f => f.field === c.name && f.operator === 'in')?.value || []" |
54 | 54 | /> |
55 | 55 |
|
|
58 | 58 | type="text" |
59 | 59 | full-width |
60 | 60 | :placeholder="$t('Search')" |
61 | | - @update:modelValue="setFilterItem({ column: c, operator: 'ilike', value: $event || undefined })" |
62 | | - :modelValue="getFilterItem({ column: c, operator: 'ilike' })" |
| 61 | + @update:modelValue="onFilterInput[c.name]({ column: c, operator: c.filterOptions?.substringSearch ? 'ilike' : 'eq', value: $event || undefined })" |
| 62 | + :modelValue="getFilterItem({ column: c, operator: c.filterOptions?.substringSearch ? 'ilike' : 'eq' })" |
63 | 63 | /> |
64 | 64 |
|
65 | 65 | <CustomDateRangePicker |
66 | 66 | v-else-if="['datetime', 'date', 'time'].includes(c.type)" |
67 | 67 | :column="c" |
68 | 68 | :valueStart="filtersStore.filters.find(f => f.field === c.name && f.operator === 'gte')?.value || undefined" |
69 | | - @update:valueStart="setFilterItem({ column: c, operator: 'gte', value: $event || undefined })" |
| 69 | + @update:valueStart="onFilterInput[c.name]({ column: c, operator: 'gte', value: $event || undefined })" |
70 | 70 | :valueEnd="filtersStore.filters.find(f => f.field === c.name && f.operator === 'lte')?.value || undefined" |
71 | | - @update:valueEnd="setFilterItem({ column: c, operator: 'lte', value: $event || undefined })" |
| 71 | + @update:valueEnd="onFilterInput[c.name]({ column: c, operator: 'lte', value: $event || undefined })" |
72 | 72 | /> |
73 | 73 |
|
74 | 74 | <CustomRangePicker |
75 | 75 | v-else-if="['integer', 'decimal', 'float'].includes(c.type) && c.allowMinMaxQuery" |
76 | 76 | :min="getFilterMinValue(c.name)" |
77 | 77 | :max="getFilterMaxValue(c.name)" |
78 | 78 | :valueStart="getFilterItem({ column: c, operator: 'gte' })" |
79 | | - @update:valueStart="setFilterItem({ column: c, operator: 'gte', value: $event || undefined })" |
| 79 | + @update:valueStart="onFilterInput[c.name]({ column: c, operator: 'gte', value: $event || undefined })" |
80 | 80 | :valueEnd="getFilterItem({ column: c, operator: 'lte' })" |
81 | | - @update:valueEnd="setFilterItem({ column: c, operator: 'lte', value: $event || undefined })" |
| 81 | + @update:valueEnd="onFilterInput[c.name]({ column: c, operator: 'lte', value: $event || undefined })" |
82 | 82 | /> |
83 | 83 |
|
84 | 84 | <div v-else-if="['integer', 'decimal', 'float'].includes(c.type)" class="flex gap-2"> |
85 | 85 | <Input |
86 | 86 | type="number" |
87 | 87 | aria-describedby="helper-text-explanation" |
88 | 88 | :placeholder="$t('From')" |
89 | | - @update:modelValue="setFilterItem({ column: c, operator: 'gte', value: $event || undefined })" |
| 89 | + @update:modelValue="onFilterInput[c.name]({ column: c, operator: 'gte', value: $event || undefined })" |
90 | 90 | :modelValue="getFilterItem({ column: c, operator: 'gte' })" |
91 | 91 | /> |
92 | 92 | <Input |
93 | 93 | type="number" |
94 | 94 | aria-describedby="helper-text-explanation" |
95 | 95 | :placeholder="$t('To')" |
96 | | - @update:modelValue="setFilterItem({ column: c, operator: 'lte', value: $event|| undefined })" |
| 96 | + @update:modelValue="onFilterInput[c.name]({ column: c, operator: 'lte', value: $event|| undefined })" |
97 | 97 | :modelValue="getFilterItem({ column: c, operator: 'lte' })" |
98 | 98 | /> |
99 | 99 | </div> |
@@ -127,6 +127,7 @@ import CustomRangePicker from "@/components/CustomRangePicker.vue"; |
127 | 127 | import { useFiltersStore } from '@/stores/filters'; |
128 | 128 | import Input from '@/afcl/Input.vue'; |
129 | 129 | import Select from '@/afcl/Select.vue'; |
| 130 | +import debounce from 'debounce'; |
130 | 131 |
|
131 | 132 | const filtersStore = useFiltersStore(); |
132 | 133 |
|
@@ -186,6 +187,19 @@ watch(() => props.show, (show) => { |
186 | 187 | // operator: 'like' |
187 | 188 | // } |
188 | 189 |
|
| 190 | +const onFilterInput = computed(() => { |
| 191 | + if (!props.columns) return {}; |
| 192 | +
|
| 193 | + return props.columns.reduce((acc, c) => { |
| 194 | + return { |
| 195 | + ...acc, |
| 196 | + [c.name]: debounce(({ column, operator, value }) => { |
| 197 | + setFilterItem({ column, operator, value }); |
| 198 | + }, c.filterOptions?.debounceTimeMs || 10), |
| 199 | + }; |
| 200 | + }, {}); |
| 201 | +}); |
| 202 | +
|
189 | 203 | function setFilterItem({ column, operator, value }) { |
190 | 204 |
|
191 | 205 | const index = filtersStore.filters.findIndex(f => f.field === column.name && f.operator === operator); |
|
0 commit comments