fix(select): Anzeige bei asynchron nachgeladenen Optionen nachziehen

Beim oninit war attrs.value teils keiner Option zuzuordnen, weil die
Optionen (z.B. Kundenliste) asynchron geladen werden — das Feld blieb
dauerhaft leer, da lastSyncedValue bereits gesetzt war und der Sync im
view nicht mehr griff. syncPending markiert die offene Synchronisierung
und wiederholt sie im view, bis eine passende Option existiert; Tippen
verwirft das Flag, damit die Nutzereingabe nicht überschrieben wird.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
gg committed 2026-09-24 19:14:16 +02:00
1 parent 3ba9b0a07f
commit 4d8febcc3f
1 file changed
+13 -1
+13 -1
View File
@@ -52,6 +52,11 @@ export const Select: m.ClosureComponent<iSelect> = () => {
// gesetzt; ändert sich der attrs.value von außen (z.B. Zurücksetzen
// eines Filters im Eltern-View), wird der Text im view nachgezogen.
let lastSyncedValue: any = undefined
// True, solange der attrs.value noch keinem label zugeordnet werden
// konnte — typischerweise weil die Optionen asynchron geladen werden
// und beim oninit noch leer waren. Der view wiederholt die Synchro-
// nisierung dann, bis eine passende Option existiert.
let syncPending: boolean = false
// Zeigt die Optionliste ungefiltert an, unabhängig vom Suchtext.
// Wird vom Öffnen-Button gesetzt (neben dem Clear-Button) und beim
// Tippen, bei der Auswahl und mit Escape zurückgesetzt.
@@ -77,6 +82,10 @@ export const Select: m.ClosureComponent<iSelect> = () => {
const option = options.find((o: iSelectOption) => o.value === value)
search = option ? option.label : ""
lastSyncedValue = value
// Konnte der value keinem label zugeordnet werden, bleibt die
// Synchronisierung offen und wird im view wiederholt, sobald
// die Optionen (asynchron) nachgeladen wurden.
syncPending = !option
}
/**
@@ -114,7 +123,7 @@ export const Select: m.ClosureComponent<iSelect> = () => {
// Initialisieren und bei der Optionsauswahl gesetzt. Ändert der
// Eltern-View den attrs.value (z.B. Zurücksetzen eines Filters),
// wird der angezeigte Text hier auf das neue label synchronisiert.
if (vnode.attrs.value !== lastSyncedValue) {
if (vnode.attrs.value !== lastSyncedValue || syncPending) {
syncSearchZumValue(vnode.attrs.value, vnode.attrs.options)
}
const isReadonly = vnode.attrs.readonly === true
@@ -132,6 +141,9 @@ export const Select: m.ClosureComponent<iSelect> = () => {
oninput: (e: Event) => {
if (isReadonly) { return }
search = (e.target as HTMLInputElement).value
// Der Nutzer tippt selbst — eine offene Synchronisierung
// (asynchron nachgeladene Optionen) nicht mehr nachziehen.
syncPending = false
// Tippen sucht wieder im Suchtext-Basis.
showAll = false
isOpen = true