|
2 | 2 | <datalist :id="selectFilterName">
|
3 | 3 | <!-- Select is also used as fallback for older browsers -->
|
4 | 4 | <SelectSimple
|
5 |
| - v-model="selectModel" |
| 5 | + v-model="aliasModel" |
6 | 6 | v-bind="{
|
7 | 7 | ...$attrs,
|
8 | 8 | ..._.omit(props, 'modelValue'),
|
|
23 | 23 | </datalist>
|
24 | 24 | <div v-if="supportsDatalist" class="flx --flxRow --flx-start-center --gap-5" v-bind="$attrs">
|
25 | 25 | <InputText
|
26 |
| - v-model="textModel" |
| 26 | + v-model="aliasModel" |
27 | 27 | :list="selectFilterName"
|
28 | 28 | v-bind="{
|
29 | 29 | ..._.omit(props, 'modelValue'),
|
|
40 | 40 | iconProps,
|
41 | 41 | }"
|
42 | 42 | class="--flx"
|
43 |
| - @change="handleTextInput" |
44 | 43 | />
|
45 | 44 | <ActionLink
|
46 | 45 | v-if="modelValue && selectOptions.length > 1"
|
|
115 | 114 | return `select-filter_${seed.replaceAll(" ", "") || randomId}`;
|
116 | 115 | });
|
117 | 116 | const selectOptions = computed<iFormOption[]>(() => (props.options ?? []).map(toOption));
|
118 |
| - const textModel = ref<string | number>(""); |
119 | 117 | /**
|
120 | 118 | * Prefers alias instead of value
|
121 | 119 | */
|
122 |
| - const selectModel = computed({ |
| 120 | + const aliasModel = computed({ |
123 | 121 | get: () => {
|
124 | 122 | const option = selectOptions.value.find(({ value }) => value === props.modelValue);
|
125 | 123 |
|
126 | 124 | // alias first
|
127 | 125 | return option?.alias ?? option?.value ?? "";
|
128 | 126 | },
|
129 | 127 | set(valueOrAlias: string | number) {
|
| 128 | + // This assumes that aliases are distinct enough |
| 129 | + const deburr = (v: string | number) => _.deburr(String(v)).toLowerCase(); |
| 130 | + const newModel = deburr(valueOrAlias); |
130 | 131 | // look for alias first
|
131 | 132 | const option = selectOptions.value.find(({ alias, value }) => {
|
132 |
| - return alias === valueOrAlias || value === valueOrAlias; |
133 |
| - }); |
| 133 | + const match = deburr(alias ?? value); |
134 | 134 |
|
135 |
| - if (!option) return emit("update:model-value", ""); |
| 135 | + return match === newModel; |
| 136 | + }); |
136 | 137 |
|
137 |
| - emit("update:model-value", option.value); |
138 |
| - textModel.value = option.alias || option.value; |
| 138 | + // emit if valid |
| 139 | + if (option) emit("update:model-value", option.value); |
139 | 140 | },
|
140 | 141 | });
|
141 | 142 | const isInvalid = computed<boolean>(() => {
|
|
149 | 150 | */
|
150 | 151 | function resetModel() {
|
151 | 152 | emit("update:model-value", "");
|
152 |
| - textModel.value = ""; |
153 |
| - } |
154 |
| -
|
155 |
| - /** |
156 |
| - * Handle select input |
157 |
| - * @listenerOverride select filter requires specific event handling |
158 |
| - */ |
159 |
| - function handleTextInput(e: Event) { |
160 |
| - const { target } = e as Event & { target: HTMLSelectElement }; |
161 |
| - const deburr = (v: string | number) => _.deburr(String(v)).toLowerCase(); |
162 |
| - const newModel = deburr(target.value); |
163 |
| -
|
164 |
| - // look for alias first |
165 |
| - const option = selectOptions.value.find(({ value, alias }) => { |
166 |
| - const match = deburr(alias ?? value); |
167 |
| -
|
168 |
| - return match === newModel; |
169 |
| - }); |
170 |
| -
|
171 |
| - if (!option) return emit("update:model-value", ""); |
172 |
| -
|
173 |
| - emit("update:model-value", option.value); |
174 |
| - textModel.value = option.alias ?? option.value; |
175 | 153 | }
|
176 | 154 |
|
177 | 155 | // lifecycle
|
178 | 156 | if (isBrowser) supportsDatalist.value = !!HTMLDataListElement;
|
179 |
| - // Populate text model |
180 |
| - if (props.modelValue) { |
181 |
| - const option = selectOptions.value.find(({ value }) => value === props.modelValue); |
182 |
| -
|
183 |
| - if (option) textModel.value = option.alias ?? option.value; |
184 |
| - } |
185 | 157 | </script>
|
0 commit comments