enhancement
major
minor
major
minor
major
#29941
TL Views: Auswahlfeld, das zusätzlich einen frei eingegebenen Wert annimmt ("auswählen oder neu eingeben")
Kontext
Ein Attribut, dessen Werte sich typischerweise wiederholen - eine Klassifikation, eine Kategorie, ein Ort, die Schlagworte eines Tickets -, soll in einem Formular der React-Oberfläche (.view.xml) als Auswahlfeld angeboten werden: Der Anwender wählt einen der bekannten Werte aus der Liste oder tippt einen neuen Wert ein, der dann übernommen wird. Heute gibt es dafür nur zwei schlechte Alternativen: ein Textfeld ohne Hilfe (Schreibvarianten desselben Werts entstehen) oder ein Auswahlfeld mit fester Optionsliste (neue Werte unmöglich).
Gewünschtes Verhalten
- Das Feld sieht aus und verhält sich wie die bekannte Dropdown-Auswahl (SelectControlProvider, Darstellung dropdown): Die Liste öffnet sich auf Wunsch und wird durch Tippen gefiltert.
- Zusätzlich übernimmt das Feld den getippten Text als Wert, wenn der Anwender keine Option wählt (Enter / Verlassen des Felds mit Tab oder Klick daneben). Escape verwirft den Text. Passt der Text (ohne Rücksicht auf Groß-/Kleinschreibung und umgebende Leerzeichen) zu einer Option, wird diese Option gewählt, so dass keine Schreibvarianten entstehen. Passt keine Option, bietet die Liste am Ende einen Eintrag „‚xyz‘ übernehmen“ an.
- Ein mehrwertiges Attribut wird so zum Schlagwortfeld: Jeder übernommene Text kommt als weiterer Wert hinzu (derselbe Text zweimal ergibt einen Wert).
- Die Optionen kommen aus den üblichen Quellen, z.B. alle bisher verwendeten Werte des Attributs über <options> mit <options-by-expression>; ohne eigene Optionen bietet das Feld die Werte an, die es hält.
- Für ein Attribut eines einfachen Typs mit Textdarstellung (Text, ganze Zahl, Kommazahl, Datum) wird der getippte Text im Format des Attributs gelesen; ein Text, der kein Wert des Typs ist, wird mit einer Meldung abgelehnt.
- Für eine Referenz (z.B. Ticket -> Schlagwort-Objekt) legt eine konfigurierte TL-Script-Funktion aus dem Text ein neues Objekt an. Das Objekt entsteht zunächst nur im Bearbeitungspuffer des Formulars und wird erst beim Speichern persistent angelegt; Abbrechen verwirft es.
Lösung
- Annotation <free-entry> am Attribut (TLFreeEntry): Ein so annotiertes Attribut wird überall, wo es bearbeitet wird, als Dropdown-Auswahl mit freier Eingabe angeboten - ohne Konfiguration in der .view.xml. Optional create: eine Funktion text -> self -> ..., die aus dem Text den Wert macht, z.B. {{{
<free-entry create="text -> self -> new(my:Keyword, transient: true)..set(my:Keyword#name, $text)"/> }}} Ohne create ist die Annotation nur an Attributen eines einfachen Typs mit Textdarstellung erlaubt; an anderen Attributen wird sie beim Laden des Modells mit einer Fehlermeldung verworfen.
- Prüfung beim Laden des Modells: Neue allgemeine Schnittstelle TLAnnotationTargetCheck, mit der eine Annotation anhand ihrer eigenen Einstellungen entscheidet, ob sie zum Attribut passt; ModelResolver ruft sie neben der @TargetType-Prüfung auf.
- Abweichung an einem einzelnen Feld: SelectControlProvider hat ein optionales Element <free-entry create="..." inputs="..." enabled="..."/>. Es überschreibt nur, was es angibt: enabled="false" schaltet die freie Eingabe für dieses Feld ab, create ersetzt die Funktion der Annotation. Das Skript folgt den Konventionen einer Ansicht: es sieht $text, $self und die Werte der mit inputs genannten Kanäle - so kann ein Feld z.B. einen Wert aus der Ansicht übernehmen, den das Modell nicht kennt.
- Reihenfolge der Control-Auswahl eines Attributs: Control am Feld, <input-control>-Annotation, <free-entry>-Annotation (Auswahl), Control des Typs, Struktur des Attributs.
- ReactDropdownSelectControl erhält das Kommando enterText und den Zustand freeEntry. Der Server erkennt passende Optionen sowie bereits im selben Formular angelegte Werte, solange das Feld sie hält. Aufgezeichnete UI-Skripte speichern den Text unverändert. Für ein mehrwertiges Attribut mit <string-set-storage/> wird ein Text mit Komma (Trennzeichen der Speicherung) mit einer Meldung abgelehnt.
- Client: TLDropdownSelect und der MUI-Adapter (Autocomplete mit freeSolo).
- Dokumentation: Entwicklerartikel view-layer/forms, Abschnitt zur Auswahl mit eigenem Text.
- Demo (tl-demo-react, Tickets): Kategorie (ein Text), Tags (mehrere Texte), Aufwand (Zahl) und Schlagwörter (Referenz auf neue Schlagwort-Objekte), alle über die Annotation im Modell. Das Feld Schlagwörter überschreibt die Funktion: der Katalog eines neuen Schlagworts kommt aus einer Auswahl der Ansicht („Katalog für neue Schlagwörter“).
- Behobene Mängel auf dem Weg:
- Ein am Feld in der .view.xml konfiguriertes input-control bestimmte zwar das Control, nicht aber das Feldmodell: ein Auswahl-Control an einem String-Attribut ohne Optionen-Annotation scheiterte. Das Feldmodell folgt jetzt dem am Feld genannten Control.
- BufferSave legte neue (transiente) Objekte nur an, wenn sie über eine Komposition erreicht wurden; ein neues Objekt in einer normalen Referenz ging beim Speichern verloren. Es wird jetzt ohne Kontext angelegt (mit dem Anlegerecht am globalen Sicherheitswurzelobjekt).
- Das Speichern eines Formulars (FormControl) ging an BufferSave vorbei; es speichert den Bearbeitungspuffer jetzt über BufferSave.