|
2 | 2 | <datalist :id="selectFilterName">
|
3 | 3 | <!-- Select is also used as fallback for older browsers -->
|
4 | 4 | <SelectSimple
|
5 |
| - v-model="model" |
| 5 | + v-model="selectModel" |
6 | 6 | v-bind="{
|
7 | 7 | ...$attrs,
|
8 | 8 | ..._.omit(props, 'modelValue'),
|
|
29 | 29 | ..._.omit(props, 'modelValue'),
|
30 | 30 | type: 'text',
|
31 | 31 | placeholder: t('select_filter_options'),
|
32 |
| - disabled: (!!model && !isInvalid) || disabled, |
| 32 | + disabled: (!!modelValue && !isInvalid) || disabled, |
33 | 33 | hidden,
|
34 | 34 | size,
|
35 | 35 | active,
|
|
40 | 40 | iconProps,
|
41 | 41 | }"
|
42 | 42 | class="--flx"
|
43 |
| - @change="handleInputChange" |
| 43 | + @change="handleTextInput" |
44 | 44 | />
|
45 | 45 | <ActionLink
|
46 |
| - v-if="model && selectOptions.length > 1" |
| 46 | + v-if="modelValue && selectOptions.length > 1" |
47 | 47 | :theme="theme"
|
48 | 48 | :disabled="disabled"
|
49 | 49 | :aria-label="t('select_restablish_field')"
|
|
57 | 57 |
|
58 | 58 | <script setup lang="ts">
|
59 | 59 | import type { IconName } from "@fortawesome/fontawesome-common-types";
|
60 |
| - import { computed, ref, watch } from "vue"; |
| 60 | + import { computed, ref } from "vue"; |
61 | 61 | import _ from "lodash";
|
62 | 62 |
|
63 | 63 | import type { iFormIconProps, iFormOption } from "@open-xamu-co/ui-common-types";
|
|
117 | 117 | const selectOptions = computed<iFormOption[]>(() => (props.options ?? []).map(toOption));
|
118 | 118 | const textModel = ref<string | number>("");
|
119 | 119 | /**
|
120 |
| - * Input model |
| 120 | + * Prefers alias instead of value |
121 | 121 | */
|
122 |
| - const model = computed({ |
| 122 | + const selectModel = computed({ |
123 | 123 | get: () => {
|
124 |
| - return props.modelValue; |
125 |
| - }, |
126 |
| - set: (newModel) => { |
127 |
| - emit("update:model-value", newModel); |
| 124 | + const option = selectOptions.value.find(({ value }) => value === props.modelValue); |
128 | 125 |
|
| 126 | + // alias first |
| 127 | + return option?.alias ?? option?.value ?? ""; |
| 128 | + }, |
| 129 | + set(valueOrAlias: string | number) { |
129 | 130 | // look for alias first
|
130 |
| - const option = selectOptions.value.find(({ value }) => value === newModel); |
| 131 | + const option = selectOptions.value.find(({ alias, value }) => { |
| 132 | + return alias === valueOrAlias || value === valueOrAlias; |
| 133 | + }); |
131 | 134 |
|
132 |
| - if (option) textModel.value = option.alias || option.value; |
| 135 | + if (!option) return emit("update:model-value", ""); |
| 136 | +
|
| 137 | + emit("update:model-value", option.value); |
| 138 | + textModel.value = option.alias || option.value; |
133 | 139 | },
|
134 | 140 | });
|
135 | 141 | const isInvalid = computed<boolean>(() => {
|
136 |
| - const option = selectOptions.value.find(({ value }) => value === model.value); |
| 142 | + const option = selectOptions.value.find(({ value }) => value === props.modelValue); |
137 | 143 |
|
138 |
| - return (model.value && !option) || props.invalid; |
| 144 | + return (props.modelValue && !option) || props.invalid; |
139 | 145 | });
|
140 | 146 |
|
141 | 147 | /**
|
142 | 148 | * Clears up input model
|
143 | 149 | */
|
144 | 150 | function resetModel() {
|
145 |
| - model.value = ""; |
| 151 | + emit("update:model-value", ""); |
146 | 152 | textModel.value = "";
|
147 | 153 | }
|
148 | 154 |
|
149 | 155 | /**
|
150 | 156 | * Handle select input
|
151 | 157 | * @listenerOverride select filter requires specific event handling
|
152 | 158 | */
|
153 |
| - function handleInputChange(e: Event) { |
| 159 | + function handleTextInput(e: Event) { |
154 | 160 | const { target } = e as Event & { target: HTMLSelectElement };
|
155 | 161 | const deburr = (v: string | number) => _.deburr(String(v)).toLowerCase();
|
156 | 162 | const newModel = deburr(target.value);
|
|
162 | 168 | return match === newModel;
|
163 | 169 | });
|
164 | 170 |
|
165 |
| - if (option) model.value = option.value; |
166 |
| - else if (model.value) model.value = ""; |
| 171 | + if (!option) return emit("update:model-value", ""); |
| 172 | +
|
| 173 | + emit("update:model-value", option.value); |
| 174 | + textModel.value = option.alias ?? option.value; |
167 | 175 | }
|
168 | 176 |
|
169 | 177 | // lifecycle
|
170 |
| -
|
171 | 178 | if (isBrowser) supportsDatalist.value = !!HTMLDataListElement;
|
| 179 | + // Populate text model |
| 180 | + if (props.modelValue) { |
| 181 | + const option = selectOptions.value.find(({ value }) => value === props.modelValue); |
172 | 182 |
|
173 |
| - watch( |
174 |
| - selectOptions, |
175 |
| - (newOptions) => { |
176 |
| - const option = newOptions.find(({ value }) => value === props.modelValue); |
177 |
| -
|
178 |
| - if (option) textModel.value = option.alias || option.value; |
179 |
| - }, |
180 |
| - { immediate: true } |
181 |
| - ); |
| 183 | + if (option) textModel.value = option.alias ?? option.value; |
| 184 | + } |
182 | 185 | </script>
|
0 commit comments