Picker — Such-Dialog, der mehrere Felder füllt¶
Wenn eine Auswahlliste nicht reicht — weil die Menge zu groß ist oder weil
mit einer Auswahl gleich mehrere Felder gesetzt werden sollen
(Lieferantennummer + Name + Telefon + E-Mail) — kommt kc:picker zum
Einsatz. Neben dem Feld erscheint ein …-Knopf; er öffnet einen
Such-Dialog mit Trefferliste zum Blättern.
Mehrere Zeilen statt mehrerer Felder
Dieselbe Konfiguration kann auch umgekehrt arbeiten: Ist das Feld vom
Typ array, kreuzt man im Dialog mehrere Zeilen an, und alle gewählten
Werte landen in diesem einen Feld. Beschrieben unter
Mehrere Werte in einem Feld.
Zusammenklicken reicht — das JSON ist zum Nachschauen da
Einen Such-Dialog auf eine Tabelle oder ein LDAP-Verzeichnis richtest du
vollständig im Formular-Editor ein, ohne eine Zeile zu tippen: Datenquelle,
Tabelle, Filter, Such- und Anzeigespalten, die Übernahme in die Felder und
die Sortierung. Nur die beiden freien Quellen — eine eigene sql-Abfrage
und der Skript-Picker — werden als JSON gepflegt; das steht weiter unten
jeweils dabei.
Die eingeklappten Kästen „Hinter den Kulissen" auf dieser Seite zeigen, was der Editor dabei in das Formular schreibt. Aufklappen lohnt sich, wenn du ein Formular exportieren und mitnehmen willst oder wissen möchtest, warum ein übernommener Wert nicht ankommt — zum Arbeiten brauchst du es nicht.
Wann Picker, wann Lookup?¶
| Situation | Variante |
|---|---|
| 5–50 Einträge, ein Wert | Lookup (Auswahlliste) |
| Hunderte oder Tausende Einträge | kc:picker |
| Mehrere Felder auf einmal setzen | immer kc:picker |
| Anwender soll suchen können | kc:picker |
Lookup und Picker lassen sich am selben Feld kombinieren (Liste plus …-Knopf).
Im Formular-Editor¶
Eigenschaften-Dialog → Reiter Auswahl → Auswahl-Typ Such-Dialog.
Dort klickst du Datenquelle, Tabelle, Filter, Such- und Anzeigespalten, die
Übernahme in die Felder (set) und die Sortierung zusammen. Nur der freie
sql-Modus und Skript-Picker werden als JSON gepflegt.
Was der Editor dabei hinterlegt¶
Was du im Reiter „Auswahl" zusammenklickst, notiert der Editor am Feld als
Eigenschaft namens kc:picker. Darin steht der ganze Dialog beschrieben: aus
welcher Tabelle er liest, in welchen Spalten das Suchfeld sucht, welche
Spalten der Anwender in der Trefferliste sieht, welche Formularfelder beim
Anklicken einer Zeile gefüllt werden, wonach sortiert wird und wie viele
Treffer eine Seite zeigt.
Hinter den Kulissen: vollständiger Such-Dialog auf eine Lieferantentabelle
{
"lieferantennummer": {
"type": "string", "title": "Lieferanten-Nr.",
"kc:picker": {
"title": "Lieferant suchen",
"table": "vendor",
"search": ["vendor_no", "name"],
"columns": [
{ "column": "vendor_no", "title": "Nr." },
{ "column": "name", "title": "Lieferant" },
{ "column": "phone", "title": "Telefon" }
],
"set": {
"lieferantennummer": "vendor_no",
"lieferantenName": "name",
"lieferantenTelefon": "phone",
"lieferantenMail": "email"
},
"orderBy": "name ASC",
"pageSize": 20
}
}
}
Klick auf … → Dialog mit Suchfeld und Trefferliste. Ein Klick auf eine
Zeile schreibt die Werte in die unter set genannten Felder.
Die Bausteine eines Such-Dialogs¶
| Schlüssel | Pflicht | Bedeutung |
|---|---|---|
table oder sql oder script oder ldapConnector |
ja | Datenquelle |
search |
ja | Spalten, in denen das Suchfeld sucht (Teiltreffer) |
columns |
ja | im Dialog angezeigte Spalten — column, optional title |
set |
ja | Übernahme: Formularfeld → Quelle |
where |
nein | fester Filter (nur mit table) |
orderBy |
nein | Sortierung der Trefferliste |
pageSize |
nein | Treffer je Seite (Standard 12, höchstens 100) |
title |
nein | Titel des Dialogs |
dataSourceId |
nein | eine externe Datenquelle statt der KCForms-Datenbank |
Worin gesucht wird¶
Das Suchfeld erzeugt WHERE col1 LIKE ? OR col2 LIKE ? … mit
%eingabe%. Ob Groß- und Kleinschreibung eine Rolle spielt, bestimmt die
Datenbank (bei MySQL mit der Standard-Sortierung nicht). Ein führendes %
nutzt keinen Index — bei sehr großen Tabellen die Suchspalten sparsam
wählen.
Was im Dialog zu sehen ist¶
Reihenfolge im Array = Reihenfolge im Dialog. Ohne title steht der
Spaltenname als Überschrift. Spalten in columns müssen nicht in set
vorkommen und umgekehrt.
Mehrere Felder auf einmal füllen¶
Der eigentliche Mehrwert: eine Zuordnung vom Formularfeld zur Quelle. Links steht jeweils das Feld im Formular, rechts die Spalte, aus der sein Wert kommt. Die Zielfelder müssen im Schema existieren — meist als schreibgeschützte Felder, damit niemand den übernommenen Wert von Hand verändert.
Hinter den Kulissen: Übernahme-Zuordnung und die Zielfelder dazu
"set": {
"lieferantennummer": "vendor_no",
"lieferantenName": "name",
"lieferantenTelefon": "phone"
}
Und die zugehörigen Zielfelder im Schema:
Im Formular-Editor bietet die set-Zeile die vorhandenen Feldnamen zur Auswahl an.
Was übernommen wird: Spalte, Textvorlage oder Datum¶
| Quelle | Beispiel | Ergebnis |
|---|---|---|
| Spalte | "FIRST_NAME" |
Wert der Spalte |
| Textvorlage | "{LAST_NAME}, {FIRST_NAME} ({LOGIN_NAME})" |
{SPALTE} wird aus der Zeile ersetzt → „Fischer, Horst (hfischer)" |
@today |
"@today" |
heutiges Datum (JJJJ-MM-TT, passt zu format: date) |
@now |
"@now" |
Datum + Uhrzeit (JJJJ-MM-TT HH:mm) |
So entsteht eine zusammengesetzte Anzeige oder ein Auswahldatum ohne
SQL. Im Formular-Editor bietet die set-Zeile dafür ein Menü („Textvorlage {…}
zusammensetzen", „Heutiges Datum", „Datum + Uhrzeit"); Spalten-Chips fügen
die Platzhalter per Klick ein.
Datenquellen¶
Eine Tabelle auswählen¶
KCForms baut die Abfrage selbst: Aus Tabelle, Suchspalten, Anzeigespalten
und Sortierung entsteht ein SELECT mit LIKE-Bedingungen und einer
seitenweisen Begrenzung — du musst dafür kein SQL schreiben.
Hinter den Kulissen: Tabellen-Konfiguration und das SQL, das daraus wird
{
"table": "vendor",
"search": ["vendor_no", "name"],
"columns": [{ "column": "vendor_no" }, { "column": "name" }],
"set": { "lieferantennummer": "vendor_no" }
}
ergibt sinngemäß:
Tabellen- und Spaltennamen müssen gültige SQL-Bezeichner sein.
Einen festen Filter setzen¶
Mit where schränkst du die Trefferliste dauerhaft ein — etwa auf aktive
Benutzerkonten, damit gesperrte gar nicht erst auftauchen.
Hinter den Kulissen: Personensuche, auf aktive Konten begrenzt
Der Filter wird mit der Suche per AND verknüpft. Er kennt keine
${feld}-Platzhalter und wird auf Lese-Anweisungen geprüft (kein DELETE,
UPDATE, ;). Für feldabhängige Filter den sql-Modus verwenden.
Eine eigene SQL-Abfrage¶
Für Joins, CASE oder COALESCE schreibst du die Abfrage selbst — dieser
Modus wird als JSON gepflegt, nicht im Editor zusammengeklickt. Alles, was
die Abfrage liefert, steht danach als Spalte zur Verfügung, auch berechnete:
im Beispiel eine „Preisklasse", die es in der Tabelle gar nicht gibt.
Hinter den Kulissen: Artikelsuche mit berechneter Preisklasse
{
"sql": "SELECT artikelnr, bezeichnung, preis, CASE WHEN preis > 10 THEN 'hochpreisig' ELSE 'Standard' END AS preisklasse FROM bueromaterial",
"search": ["artikelnr", "bezeichnung"],
"columns": [
{ "column": "artikelnr", "title": "Nr." },
{ "column": "bezeichnung", "title": "Bezeichnung" },
{ "column": "preisklasse", "title": "Preisklasse" }
],
"set": { "artikel": "artikelnr" }
}
Die Abfrage muss mit SELECT oder WITH beginnen; Schreibbefehle werden
abgelehnt. Bei Joins in search die Alias-Schreibweise (b.bezeichnung)
nutzen.
Ein LDAP-Verzeichnis¶
Statt einer Tabelle durchsucht der Dialog ein Verzeichnis: Du wählst den
Konnektor, den Ast, ab dem gesucht wird, und den Filter; search und
columns nennen dann Verzeichnis-Attribute statt Tabellenspalten.
Hinter den Kulissen: Personensuche über einen LDAP-Konnektor
{
"title": "Person suchen",
"ldapConnector": "kcads",
"ldapBase": "ou=Users,dc=kcforms,dc=test",
"ldapFilter": "(objectClass=inetOrgPerson)",
"search": ["cn", "mail", "uid"],
"columns": [
{ "column": "cn", "title": "Name" },
{ "column": "mail", "title": "E-Mail" }
],
"set": { "person": "uid", "personMail": "mail" }
}
Der Suchbegriff wird als Teiltreffer-Filter über die search-Attribute
angehängt. Die Spalte dn liefert den DN des Eintrags. Konnektoren
richtest du unter LDAP ein.
Ein Skript¶
Für Daten aus einem Webservice oder berechnete Listen baust du die Trefferliste per JavaScript zusammen und meldest jede Zeile einzeln an. Auch dieser Modus wird als JSON gepflegt.
Hinter den Kulissen: Trefferliste aus einem Skript
{
"kc:picker": {
"title": "Land suchen",
"search": ["code", "label"],
"columns": [
{ "column": "code", "title": "ISO" },
{ "column": "label", "title": "Land" }
],
"set": { "land": "code", "landName": "label" },
"script": "db.query('SELECT code, label FROM country').forEach(function (r) { handle({ code: r.code, label: r.label }); });"
}
}
Im Skript stehen handle({ … }) (eine Zeile hinzufügen), db, log und
kc zur Verfügung. Das Skript darf mindestens 30 Sekunden laufen. Bei
großen Listen lohnt es sich, schon im Skript zu filtern.
Picker in Detail-Tabellen¶
In einer Spalte einer Detail-Tabelle
funktioniert der Picker genauso. set bezieht sich dann auf Spalten
derselben Zeile: Im Beispiel unten sucht der Anwender in der Spalte
„Artikel-Nr." einen Artikel — übernommen werden Nummer und Preis, beide in
die Zeile, in der er gerade steht.
Hinter den Kulissen: Artikel-Picker in einer Bestellpositions-Tabelle
"positionen": {
"type": "array",
"kc:childTable": {
"properties": {
"bestellnr": {
"type": "string", "title": "Artikel-Nr.",
"kc:picker": {
"table": "bueromaterial",
"search": ["artikelnr", "bezeichnung"],
"columns": [
{ "column": "artikelnr", "title": "Nr." },
{ "column": "bezeichnung", "title": "Bezeichnung" },
{ "column": "preis", "title": "Preis" }
],
"set": { "bestellnr": "artikelnr", "preis": "preis" }
}
},
"menge": { "type": "number", "kc:decimals": 0 },
"preis": { "type": "number", "kc:decimals": 2, "kc:readonly": true }
},
"initialRows": 1
}
}
Blättern¶
Standard sind 12 Treffer je Seite, höchstens 100. Der Dialog zeigt die Gesamtzahl der Treffer und lädt weitere Seiten vom Server nach.
Vollständiges Beispiel¶
Zum Abschluss ein ganzes Bestellformular: Bestellnummer, ein auf das heutige Datum vorbelegtes Bestelldatum und ein Lieferantenfeld mit Such-Dialog. Daneben stehen zwei schreibgeschützte Felder für Name und Telefon, die der Dialog mitfüllt.
Hinter den Kulissen: Bestellformular mit Lieferanten-Suchdialog
{
"title": "Bestellung",
"type": "object",
"kc:layout": "horizontal-2",
"properties": {
"bestellnr": { "type": "string", "title": "Bestell-Nr." },
"bestelldatum": { "type": "string", "format": "date", "title": "Datum",
"kc:defaultExpression": "new Date().format('yyyy-MM-dd')" },
"lieferantennummer": {
"type": "string", "title": "Lieferant",
"kc:picker": {
"title": "Lieferant suchen",
"table": "vendor",
"search": ["vendor_no", "name"],
"columns": [
{ "column": "vendor_no", "title": "Nr." },
{ "column": "name", "title": "Name" },
{ "column": "phone", "title": "Telefon" }
],
"set": {
"lieferantennummer": "vendor_no",
"lieferantenName": "name",
"lieferantenTelefon": "phone"
},
"orderBy": "name ASC",
"pageSize": 20
}
},
"lieferantenName": { "type": "string", "kc:readonly": true, "title": "Name" },
"lieferantenTelefon": { "type": "string", "kc:readonly": true, "title": "Telefon" }
},
"required": ["lieferantennummer"]
}
Klick auf … → Suche → Zeile wählen → drei Felder sind auf einmal gefüllt.
Stolperfallen¶
set-Ziel fehlt im Schema — der Wert wird gesetzt, aber nicht gespeichert. Im Formular-Editor die Feldauswahl derset-Zeile nutzen.- Übernommene Spalte nicht in
columns— funktioniert, der Anwender sieht den Wert im Dialog aber nicht. Meist ist es besser, alle übernommenen Spalten auch anzuzeigen. - Mehrdeutige Spalten — im
sql-Modus mit Joins insearchden Alias angeben (v.namestattname). - Skript-Picker ohne eigene Filterung — liefert immer alles; bei großen Listen im Skript filtern.