Sichtbarkeits- und Pflichtbedingungen¶
Ein Formular muss nicht alles auf einmal zeigen. Ein Feld kann erst auftauchen, wenn es gebraucht wird, ein anderes erst dann zur Pflicht werden, und wieder eines kann nur zum Lesen dastehen. Genau darum geht es hier: Du legst je Feld fest, wann es sichtbar ist, wann es ausgefüllt sein muss, wann es schreibgeschützt ist — und ob sein Wert verschwindet, sobald das Feld nicht mehr zu sehen ist. Alles davon ist freiwillig; ein Feld ohne solche Angaben ist immer da.
Die Bedingungen greifen sofort: Ein Klick auf ein Kästchen lässt das abhängige Feld erscheinen oder verschwinden, ohne dass das Formular nachlädt. Beim Speichern prüft der Server dieselben Bedingungen noch einmal nach — wer ein Feld im Browser künstlich einblendet, kommt damit also nicht durch.
Zwei Wege — einer davon ganz ohne Tippen
Am Feld selbst steht die Bedingung als kurzer Ausdruck, etwa
inland_ausland === 'ausland'. Wer nicht tippen möchte, klickt sie
stattdessen einmal als benannte Regel zusammen und setzt
am Feld nur noch deren Namen ein — @Ausland. Das lohnt sich ohnehin,
sobald dieselbe Bedingung an mehreren Feldern hängt.
Die eingeklappten Kästen „Hinter den Kulissen" auf dieser Seite zeigen, was dabei in das Formular geschrieben wird. Aufklappen lohnt sich, wenn du verstehen willst, warum etwas so funktioniert — zum Arbeiten brauchst du es nicht.
Im Formular-Editor¶
Im Eigenschaften-Dialog eines Feldes, Reiter Sichtbarkeit, stehen Sichtbarkeit, Pflichtfeld und Schreibgeschützt jeweils auf ein, aus oder bedingt. Bei bedingt erscheint darunter ein Eingabefeld für die Bedingung; ganz unten im selben Reiter sitzen die Schalter Wert leeren, sobald unsichtbar und Im PDF erscheinen.

Das Bild zeigt das Feld zielland aus dem Beispiel Reisekostenabrechnung:
Es erscheint nur bei einer Auslandsreise, ist dann Pflicht, und sein Wert
verschwindet wieder, sobald es sich ausblendet. Alle drei Angaben verweisen auf
dieselbe Regel @Ausland.
Beim Tippen hilft das Eingabefeld mit: Es schlägt vorhandene Regeln vor und
hebt erkannte @Name-Referenzen grün hervor — ein Tippfehler im Regelnamen
fällt damit sofort auf.
Klicken statt tippen: der Baukasten der Regeln¶
Der visuelle Bedingungs-Baukasten sitzt nicht am Feld, sondern bei den Regeln in den Formular-Eigenschaften. Dort klickst du eine Bedingung aus Bausteinen zusammen:
| Bedingungsart | Beispiel |
|---|---|
| Element (Wertvergleich) | anrede ist gleich Firma |
| Benutzer / Gruppe / Berechtigung | angemeldeter Benutzer ist in Gruppe Sachbearbeiter |
| Referenz auf andere Regel | @IstFirma |
| Verschachtelte Gruppe | (A oder B) und C |
| JavaScript | freier Ausdruck |
Bedingungen lassen sich mit UND/ODER verknüpfen und einzeln invertieren (NICHT). Der Baukasten schreibt daraus den fertigen Ausdruck, und am Feld genügt anschließend der Regelname.

Was der Anwender davon sieht¶
Im ausgefüllten Formular greift die Bedingung sofort. Solange Inland gewählt ist, gibt es das Feld Zielland nicht:

Mit der Auswahl Ausland erscheint es — und trägt den roten Stern, ist also auszufüllen:

Bleibt es dann leer, meldet die Prüfung es an — die Pflicht gilt erst, seit das Feld sichtbar ist:

Was der Editor dabei hinterlegt¶
Was du im Reiter „Sichtbarkeit" zusammenklickst, notiert der Editor am Feld als eine der folgenden Eigenschaften. Du musst sie nie von Hand schreiben — aber sie zu kennen zahlt sich zweimal aus: Bedingungen reisen mit dem Formular mit (Export/Import), und wenn eine Regel nicht greift, zeigt ein Blick auf diese Eigenschaften, welcher Ausdruck tatsächlich am Feld hängt.
| Attribut | Wirkung | Default |
|---|---|---|
kc:visibleIf |
Dynamische Sichtbarkeit. Der Ausdruck wird live ausgewertet — sobald das Ergebnis truthy ist, wird das Feld gerendert; falsy versteckt es. | sichtbar (kein Filter) |
kc:requiredIf |
Dynamische Pflichtfeld-Markierung. Truthy → Feld bekommt das Sternchen und wird in der Validierung als Pflichtfeld behandelt. | optional (kein Pflichtfeld) |
kc:readonlyIf |
Dynamischer Schreibschutz. Truthy → Feld ist schreibgeschützt. | beschreibbar |
kc:clearIfInvisible |
Wenn true: sobald das Feld unsichtbar wird, setzt der Renderer den Wert automatisch auf null. Verhindert „Datenleichen" hinter ausgeblendeten Feldern. |
false (Wert bleibt erhalten) |
kc:clearIfInvisibleIf |
wie kc:clearIfInvisible, aber nur unter einer Bedingung |
— |
kc:printableIf |
Feld erscheint nur im PDF, wenn die Bedingung zutrifft | druckbar |
Statisch vs. dynamisch: Daneben gibt es kc:required: true
(immer Pflicht) und kc:visible: false (immer unsichtbar). Beide
schalten ihr Verhalten hart ein/aus, ohne Bedingung. Eine Kombination
mit den dynamischen Varianten ist erlaubt — die statische Form
gewinnt im Zweifel.
Wie eine Bedingung aufgebaut ist¶
Sowohl kc:visibleIf als auch kc:requiredIf erwarten einen
JavaScript-Ausdruck als String. Der Wert wird ausgewertet und als
Boolean interpretiert (truthy / falsy nach JS-Semantik mit ein paar
formularfreundlichen Verfeinerungen).
Was steht im Ausdruck zur Verfügung?¶
- Feldnamen direkt — jeder Eigenschaftsname aus
propertiesist als lokale Variable verfügbar (sofern der Name ein gültiger JS-Identifier ist). values— das gesamte Werte-Objekt als read-onlyfrozenObject. Nützlich für Feldnamen mit Punkten oder Sonderzeichen:values["adr.strasse"].kc.num(v)— tolerantes Number-Parsing."1,50"→1.5,"1.234,56"→1234.56, leerer String →0, ungültige Eingabe →0.kc.isEmpty(v)—truefürnull,undefined,""oder Whitespace-only.kc.text(v)— null-sichere Trim-View, immer String.ctx.attachments— die Dateianlagen des Datensatzes, z. B.ctx.attachments.length > 0.@Regelname— eine benannte Regel; wird vor der Auswertung durch ihren Ausdruck ersetzt.
Operator-Übersicht¶
| Operator | Bedeutung | Beispiel |
|---|---|---|
|| |
Logisches ODER | aktiv || archiv |
&& |
Logisches UND | verheiratet && hatKinder |
=== |
Strikte Gleichheit | anrede === "Firma" |
!== |
Strikte Ungleichheit | typ !== "intern" |
== |
Lockere Gleichheit (Number ↔ String) | alter == "18" |
!= |
Lockere Ungleichheit | plz != "" |
< > <= >= |
Numerische Vergleiche | betrag > 1000 |
! |
Negation | !geschaeftskunde |
( ) |
Gruppierung | (a || b) && c |
?. |
Optional Chaining | plz?.startsWith("01") |
Wann ein Wert als „wahr" gilt (formularfreundlich)¶
true/ Checkbox angehakt → truthyfalse/ Checkbox nicht angehakt → falsy- Leerer String
""→ falsy; nur Whitespace → falsy - Der String
"false"→ falsy (manche Backends liefern Booleans als String) null/undefined→ falsy0→ falsy; jede andere Zahl → truthy
Sicherheit und Sandboxing¶
Die Ausdrücke werden im Browser via new Function() ausgeführt —
also echte ECMAScript-Auswertung mit den vollen Sprachfeatures.
Damit dabei nichts schiefgeht, sind mehrere Schutzmaßnahmen aktiv:
- Strict mode —
'use strict'steht im Function-Body. Implizite Globals wiefoo = 5(ohnelet/const) werfen sofort. valuesist frozen —Object.freezeverhindert versehentliche Mutationen.values.feldname = "neu"wirft einen TypeError, der Ausdruck fällt auf den Default zurück.thisistundefined—new Functionsetzt das beim Aufruf so.- Cache pro Ausdruck — kompilierte Funktionen werden gespeichert und auf Folge-Renders wiederverwendet. Kein Re-Parse pro Tastendruck.
- Defensive Fallbacks — Parse- oder Laufzeitfehler werden
geloggt (Browser-Konsole), das Feld bekommt seinen sicheren Default
(
truefürvisibleIf,falsefürrequiredIf). Ein Tippfehler im Ausdruck legt nie das ganze Formular lahm.
Vertrauensgrenze
Schema-Autoren sind Admins/Entwickler — Endanwender schreiben
keine Ausdrücke. Wer das Schema gestaltet, hat dieselbe Macht
wie das Backend-onLoad-Skript. Ausdrücke unterliegen keinem
zusätzlichen Whitelist-Filter, das ist bewusst so, weil es die
kreative Nutzung nicht einschränken soll.
Die kc-Helfer im Detail¶
kc.num(v) — robuste Zahlenkonversion¶
Liefert eine finite Zahl, niemals NaN. Ideal für numerische
Vergleiche an Eingabefeldern, die als String-Eingaben starten.
kc.num(42) // → 42
kc.num("42") // → 42
kc.num("1,50") // → 1.5 (Komma als Dezimaltrenner)
kc.num("1.234,56") // → 1234.56 (der letzte Trenner ist das Dezimalzeichen)
kc.num("") // → 0
kc.num(null) // → 0
kc.num("abc") // → 0
kc.num rechnet in Bedingungen genauso wie in Skripten (siehe
kc-Helfer). Zahlenfelder
(type: number) stehen Bedingungen ohnehin schon als echte Zahl bereit —
auch wenn sie formatiert angezeigt werden; kc.num brauchst du vor allem für
Textfelder.
kc.isEmpty(v) — null-/leer-Check¶
Behandelt null, undefined, leeren String und reinen
Whitespace-String einheitlich als „leer". Booleans und Zahlen sind
nie leer.
kc.isEmpty(null) // → true
kc.isEmpty(undefined) // → true
kc.isEmpty("") // → true
kc.isEmpty(" ") // → true
kc.isEmpty("Hallo") // → false
kc.isEmpty(0) // → false (0 ist kein "leerer Wert")
kc.isEmpty(false) // → false
kc.text(v) — Trim-View¶
Konvertiert beliebigen Wert in einen getrimmten String. Praktisch für Vergleiche bei Eingabefeldern, in denen Nutzer Leerzeichen tippen könnten.
kc.text(null) // → ""
kc.text(" Hallo ") // → "Hallo"
kc.text(42) // → "42"
kc.text(true) // → "true"
Fallbeispiele¶
Die folgenden Beispiele zeigen typische Muster aus realen Formularen. Jedes beschreibt zuerst, was der Anwender im fertigen Formular erlebt — der aufklappbare Kasten darunter zeigt dazu das Schema. Jedes Beispiel ist eigenständig; du kannst es direkt in dein Schema kopieren, wenn du lieber tippst als klickst.
Klassiker: Geburtsname nur bei Bedarf¶
Eine Checkbox steuert, ob das Geburtsname-Feld erscheint. Wenn der Nutzer die Checkbox abhakt, soll der Wert gelöscht werden — und nur wenn die Checkbox gesetzt ist, ist der Geburtsname Pflicht.
Im Editor: am Feld Geburtsname die Sichtbarkeit auf bedingt stellen und den Namen der Checkbox als Bedingung eintragen, dasselbe beim Pflichtfeld, und zusätzlich Wert leeren, sobald unsichtbar einschalten.
Hinter den Kulissen: Feld nur zeigen, wenn ein Kästchen angehakt ist
"geburtsnameVorhanden": {
"type": "boolean",
"title": "Geburtsname vorhanden"
},
"geburtsname": {
"type": "string",
"title": "Geburtsname",
"kc:visibleIf": "geburtsnameVorhanden",
"kc:requiredIf": "geburtsnameVorhanden",
"kc:clearIfInvisible": true
}
Der Name der Checkbox steht als Bedingung schlicht für sich allein — der Wert ist bereits ein Boolean und muss mit nichts verglichen werden.
Anrede steuert Folgefelder¶
Bei der Anrede „Firma" werden andere Felder benötigt als bei einer natürlichen Person. Klassischer Wechsel zwischen zwei Feldgruppen: Vorname erscheint bei allen Anreden außer „Firma", Firmenname ausschließlich bei „Firma" — und das jeweils ausgeblendete Feld gibt seinen Wert ab.
Hinter den Kulissen: zwei Feldgruppen, die sich gegenseitig ablösen
"anrede": {
"type": "string", "title": "Anrede",
"enum": ["Herr", "Frau", "Divers", "Firma"]
},
"vorname": {
"type": "string", "title": "Vorname",
"kc:visibleIf": "anrede !== 'Firma'",
"kc:requiredIf": "anrede !== 'Firma'",
"kc:clearIfInvisible": true
},
"firmenname": {
"type": "string", "title": "Firmenname",
"kc:visibleIf": "anrede === 'Firma'",
"kc:requiredIf": "anrede === 'Firma'",
"kc:clearIfInvisible": true
}
Die beiden Bedingungen sind exakt gegenläufig (!== gegen ===) — damit
ist immer genau eine der beiden Feldgruppen sichtbar.
Inland/Ausland — gegenseitig ausschließende Adressfelder¶
Je nach Wohnsitz braucht es unterschiedliche Adress-Detailfelder: bei inland das Bundesland, bei ausland den Staat. Der Renderer räumt jeweils das nicht-passende Feld weg.
Hinter den Kulissen: Auswahlfeld schaltet zwischen Bundesland und Staat
"wohnsitz": {
"type": "string", "title": "Wohnsitz",
"enum": ["inland", "ausland"]
},
"bundesland": {
"type": "string", "title": "Bundesland",
"kc:visibleIf": "wohnsitz === 'inland'",
"kc:requiredIf": "wohnsitz === 'inland'",
"kc:clearIfInvisible": true
},
"staat": {
"type": "string", "title": "Staat",
"kc:visibleIf": "wohnsitz === 'ausland'",
"kc:requiredIf": "wohnsitz === 'ausland'",
"kc:clearIfInvisible": true
}
Verglichen wird gegen die Werte aus enum — also gegen den gespeicherten
Schlüssel, nicht gegen den angezeigten Text.
Mehrfach-Bedingungen mit && und ||¶
Komplexere Bedingungen — wenn beispielsweise ein Premium-Feature nur bei bestimmten Tarifen erscheinen soll, der Vertrag aber nicht gekündigt sein darf. Genauso lassen sich Telefon- und E-Mail-Feld an eine Kontaktart-Auswahl hängen, bei der „beides" beide Felder einblendet.
Als Regel zusammengeklickt entstehen solche Fälle im Baukasten als verschachtelte Gruppe: eine ODER-Gruppe für die Tarife, mit UND verknüpft mit der invertierten Kündigung.
Hinter den Kulissen: ODER-Gruppe mit UND kombiniert
"premiumOptionen": {
"type": "string", "title": "Premium-Optionen",
"kc:visibleIf": "(plan === 'pro' || plan === 'enterprise') && !kuendigung"
},
"kontaktTel": {
"type": "string", "title": "Telefon",
"kc:visibleIf": "kontaktArt === 'telefon' || kontaktArt === 'beides'",
"kc:requiredIf": "kontaktArt === 'telefon' || kontaktArt === 'beides'"
},
"kontaktEmail": {
"type": "string", "title": "E-Mail",
"kc:visibleIf": "kontaktArt === 'email' || kontaktArt === 'beides'"
}
Die Klammern sind bedeutsam: ohne sie würde && stärker binden als ||
und die Kündigung nur den letzten Tarif ausschließen.
Numerische Schwellenwerte¶
Wenn ein Eingabewert eine Grenze überschreitet, soll ein zusätzliches
Begründungsfeld erscheinen. Ab 5.000 € wird ein Genehmiger verlangt, ab
10.000 € zusätzlich eine Begründung der Höhe. kc.num kümmert sich um
String-zu-Number-Konversion bei Eingabefeldern.
Hinter den Kulissen: zwei gestaffelte Betragsgrenzen
"betrag": {
"type": "number", "title": "Betrag",
"kc:decimals": 2
},
"genehmiger": {
"type": "string", "title": "Genehmiger",
"kc:visibleIf": "kc.num(betrag) > 5000",
"kc:requiredIf": "kc.num(betrag) > 5000",
"kc:clearIfInvisible": true
},
"begruendung": {
"type": "string", "title": "Begründung der Höhe",
"kc:widget": "textarea",
"kc:visibleIf": "kc.num(betrag) >= 10000"
}
Zwei Felder mit unterschiedlichen Schwellen ergeben eine Staffel: ab 5.000 erscheint der Genehmiger, ab 10.000 kommt die Begründung dazu.
String-Methoden — Postleitzahl-basierte Logik¶
Da der Ausdruck echtes JavaScript ist, kannst du alle nativen
String-Methoden nutzen. Das Beispiel blendet einen Hinweistext ein, sobald die
Postleitzahl mit 01, 02 oder 04 beginnt, und eine Warnung, solange sie
angefangen, aber noch nicht fünfstellig ist.
Dafür gibt es keinen Klickweg — die beiden Ausdrücke tippst du am Feld ein (oder in einer Regel unter der Bedingungsart JavaScript).
Hinter den Kulissen: Hinweisfelder, die an der Postleitzahl hängen
"plz": { "type": "string", "title": "Postleitzahl" },
"sachsenHinweis": {
"type": "string", "title": "Hinweis für Sachsen",
"kc:readonly": true,
"kc:visibleIf": "plz?.startsWith('01') || plz?.startsWith('02') || plz?.startsWith('04')"
},
"plzWarnung": {
"type": "string", "title": "PLZ scheint unvollständig",
"kc:readonly": true,
"kc:visibleIf": "plz && plz.length > 0 && plz.length < 5"
}
Das Fragezeichen in plz?.startsWith ist Optional Chaining: Ist das Feld
noch leer, liefert der Ausdruck undefined statt eines Fehlers.
Minderjährigkeit + gesetzlicher Vertreter¶
Klassisches Behörden-Pattern: bei Minderjährigen muss ein gesetzlicher Vertreter erfasst werden — aber nur wenn die Vertretung nicht identisch mit dem Antragsteller ist. Erst das Häkchen Minderjährig bringt die Rückfrage nach der Identität, und erst deren Verneinung die beiden Vertreter-Felder.
Hinter den Kulissen: dreistufig aufbauende Bedingungen
"geburtsdatum": { "type": "string", "title": "Geburtsdatum", "format": "date" },
"minderjaehrig": { "type": "boolean", "title": "Minderjährig" },
"vertreterIdentisch": {
"type": "boolean", "title": "Erziehungsberechtigter = Antragsteller",
"kc:visibleIf": "minderjaehrig"
},
"vertreterName": {
"type": "string", "title": "Name des gesetzlichen Vertreters",
"kc:visibleIf": "minderjaehrig && !vertreterIdentisch",
"kc:requiredIf": "minderjaehrig && !vertreterIdentisch",
"kc:clearIfInvisible": true
},
"vertreterAnschrift": {
"type": "string", "title": "Anschrift des Vertreters",
"kc:visibleIf": "minderjaehrig && !vertreterIdentisch",
"kc:requiredIf": "minderjaehrig && !vertreterIdentisch",
"kc:clearIfInvisible": true
}
Dass dieselbe Bedingung an zwei Feldern steht, ist genau der Fall, für den sich eine benannte Regel lohnt (siehe unten).
Begründung bei Abweichung vom Standard¶
Wenn der Nutzer einen Rabatt einträgt oder eine abweichende Anschrift wählt, ist eine Begründung notwendig. Das Kommentarfeld bleibt dabei immer sichtbar — es wird lediglich zum Pflichtfeld.
Hinter den Kulissen: Pflichtfeld ohne Sichtbarkeits-Bedingung
"rabattProzent": {
"type": "number", "title": "Rabatt (%)",
"kc:decimals": 1
},
"abweichendeAnschrift": {
"type": "boolean", "title": "Abweichende Lieferanschrift"
},
"kommentar": {
"type": "string", "title": "Kommentar / Begründung",
"kc:widget": "textarea",
"kc:requiredIf": "kc.num(rabattProzent) > 0 || abweichendeAnschrift"
}
Hier steht bewusst nur kc:requiredIf und kein kc:visibleIf — das Feld
ist immer da, bekommt aber je nach Lage das Pflicht-Sternchen.
Felder mit Punkt-im-Namen¶
Manche Feldnamen — etwa aus migrierten Systemen — enthalten Punkte.
Sie sind keine gültigen JS-Identifier und müssen über values["..."]
referenziert werden. Fachlich passiert hier nichts Neues: Ein Länder-Auswahlfeld
blendet je nach Wahl das Kanton- oder das Bundesland-Feld ein.
Auch das ist ein Fall zum Tippen — in einer Regel wäre es die Bedingungsart JavaScript.
Hinter den Kulissen: Feldnamen über values[...] ansprechen
"adr.land": {
"type": "string", "title": "Land",
"enum": ["DE", "AT", "CH"]
},
"adr.kanton": {
"type": "string", "title": "Kanton (CH)",
"kc:visibleIf": "values['adr.land'] === 'CH'",
"kc:requiredIf": "values['adr.land'] === 'CH'",
"kc:clearIfInvisible": true
},
"adr.bundesland": {
"type": "string", "title": "Bundesland (AT)",
"kc:visibleIf": "values['adr.land'] === 'AT'",
"kc:clearIfInvisible": true
}
values ist das komplette Werte-Objekt. Der Zugriff in eckigen Klammern
funktioniert für jeden Feldnamen — auch für solche mit Leerzeichen oder
Umlauten.
Plausibilitäts-Hinweis (read-only Info-Feld)¶
Ein read-only-Feld als Hinweistext, das nur erscheint, wenn eine Inkonsistenz erkannt wird — hier eine Miete von mehr als 40 % des Monatseinkommens.
Hinter den Kulissen: Warnhinweis aus einem Verhältnis zweier Zahlen
"einkommen": { "type": "number", "title": "Monatseinkommen" },
"miete": { "type": "number", "title": "Monatsmiete" },
"warnungUebermiete": {
"type": "string",
"title": "⚠️ Mietbelastung sehr hoch",
"kc:readonly": true,
"kc:visibleIf": "kc.num(einkommen) > 0 && kc.num(miete) / kc.num(einkommen) > 0.4"
}
Der erste Teil der Bedingung (einkommen > 0) verhindert eine Division
durch null, solange das Einkommen noch nicht erfasst ist.
Zahlungsweise → IBAN/Karte je nach Auswahl¶
Klassisches Bezahl-Pattern: bei Lastschrift sind IBAN und Kontoinhaber Pflicht, bei Kreditkarte die Kartennummer, bei Rechnung gar nichts Zusätzliches.
Hinter den Kulissen: drei Zahlungswege mit unterschiedlichen Folgefeldern
"zahlungsweise": {
"type": "string", "title": "Zahlungsweise",
"enum": ["rechnung", "lastschrift", "kreditkarte"],
"kc:required": true
},
"iban": {
"type": "string", "title": "IBAN",
"kc:visibleIf": "zahlungsweise === 'lastschrift'",
"kc:requiredIf": "zahlungsweise === 'lastschrift'",
"kc:clearIfInvisible": true
},
"kontoinhaber": {
"type": "string", "title": "Kontoinhaber",
"kc:visibleIf": "zahlungsweise === 'lastschrift'",
"kc:requiredIf": "zahlungsweise === 'lastschrift'",
"kc:clearIfInvisible": true
},
"kartennummer": {
"type": "string", "title": "Kreditkartennummer",
"kc:visibleIf": "zahlungsweise === 'kreditkarte'",
"kc:requiredIf": "zahlungsweise === 'kreditkarte'",
"kc:clearIfInvisible": true
}
Für rechnung ist schlicht kein Folgefeld definiert — die Auswahl blendet dann alle drei Zusatzfelder aus und räumt ihre Werte weg.
Datums-Vergleich¶
Datums-Strings im ISO-Format können direkt mit < oder >
verglichen werden, weil ISO-8601 lexikographisch sortierbar ist. Im Beispiel
erscheint ein Hinweis, sobald das Geburtsdatum nach dem 1.1.2008 liegt.
Hinter den Kulissen: Hinweis ab einem festen Stichtag
"geburtsdatum": {
"type": "string", "title": "Geburtsdatum",
"format": "date"
},
"hinweisVertreter": {
"type": "string",
"title": "⚠️ Antragsteller scheint minderjährig — gesetzlichen Vertreter ergänzen",
"kc:readonly": true,
"kc:visibleIf": "geburtsdatum && geburtsdatum > '2008-01-01'"
}
Der vorangestellte Test auf geburtsdatum sorgt dafür, dass der Hinweis
bei noch leerem Feld nicht aufpoppt.
Soll die Grenze mitwandern („heute minus 18 Jahre"), rechnest du sie im Ausdruck selbst aus — es ist normales JavaScript:
"kc:visibleIf": "geburtsdatum && geburtsdatum > new Date(new Date().setFullYear(new Date().getFullYear() - 18)).toISOString().slice(0, 10)"
Für mehrfach gebrauchte Grenzen lohnt sich eine Regel.
Aufbauende Bedingungen (Folge-Schritte)¶
Mehrstufige Formulare wie ein Wizard — Schritt 2 wird erst sichtbar, wenn Schritt 1 ausgefüllt ist, Schritt 3 erst wenn Schritt 2 vollständig ist. Das Formular wächst also mit, während der Anwender es ausfüllt.
Hinter den Kulissen: Felder, die sich nacheinander freischalten
"schritt1Email": {
"type": "string", "title": "Schritt 1: E-Mail",
"format": "email", "kc:required": true
},
"schritt2Name": {
"type": "string", "title": "Schritt 2: Name",
"kc:visibleIf": "!kc.isEmpty(schritt1Email)",
"kc:requiredIf": "!kc.isEmpty(schritt1Email)"
},
"schritt3Anliegen": {
"type": "string", "title": "Schritt 3: Ihr Anliegen",
"kc:widget": "textarea",
"kc:visibleIf": "!kc.isEmpty(schritt1Email) && !kc.isEmpty(schritt2Name)",
"kc:requiredIf": "!kc.isEmpty(schritt1Email) && !kc.isEmpty(schritt2Name)"
}
!kc.isEmpty(...) statt eines nackten Feldnamens ist hier wichtig: Ein
Textfeld, in das nur Leerzeichen getippt wurden, gilt so weiterhin als
unausgefüllt.
Statisch + dynamisch kombiniert¶
Manche Felder sind grundsätzlich Pflicht, andere Bedingungen kommen
je nach Kontext dazu. Die statische Form gewinnt — wenn
kc:required: true gesetzt ist, ist das Feld immer Pflicht,
kc:requiredIf wird ignoriert.
Hinter den Kulissen: hartes Pflichtfeld neben einem bedingten
"email": {
"type": "string", "title": "E-Mail",
"format": "email",
"kc:required": true
},
"emailAlternativ": {
"type": "string", "title": "Alternative E-Mail",
"format": "email",
"kc:visibleIf": "zweiteEmailGewuenscht",
"kc:requiredIf": "zweiteEmailGewuenscht",
"kc:clearIfInvisible": true
}
Im Editor entspricht das den Schalterstellungen ein (hart) beim ersten und bedingt beim zweiten Feld.
Best Practices¶
Bedingungs-Symmetrie für Pflicht und Sichtbarkeit¶
In den meisten Fällen ist die Bedingung für „sichtbar" auch die Bedingung für „Pflicht". Halte sie identisch — sonst wäre ein Pflichtfeld unsichtbar (Nutzer wissen nicht, warum sie nicht abschicken können) oder ein sichtbares Feld plötzlich nicht mehr Pflicht.
Setze beide Attribute mit demselben Ausdruck und ergänze
kc:clearIfInvisible: true, wenn das Feld semantisch keinen Wert
tragen soll, solange es nicht sichtbar ist.
kc:clearIfInvisible nutzen, um Datenleichen zu vermeiden¶
Ohne dieses Flag bleibt der Wert eines Feldes erhalten, auch wenn es ausgeblendet wird. Beim nächsten Submit landet er in der Datenbank — und wenn der Nutzer die Trigger-Checkbox später wieder aktiviert, taucht der alte Wert wieder auf. Das ist manchmal gewünscht (Notizen für später aufheben), oft aber unerwartet.
Faustregel: immer clearIfInvisible setzen, wenn das Feld
semantisch nur in einem bestimmten Zustand existiert — z.B.
Geburtsname, Vertreter-Daten, Auslands-Felder.
Komplexe Bedingungen lieber benennen¶
Wenn dieselbe Bedingung in mehreren Feldern auftaucht, definiere sie einmal
als Regel und referenziere sie mit @Name. Am Feld steht dann
statt des ausgeschriebenen Vergleichs nur noch der sprechende Regelname.
Hinter den Kulissen: eine benannte Regel, an drei Feldern verwendet
"kc:rules": [
{ "name": "IstFirma", "expr": "anrede === 'Firma'" }
],
"firmenname": { "kc:visibleIf": "@IstFirma" },
"firmensitz": { "kc:visibleIf": "@IstFirma" },
"firmensteuer": { "kc:visibleIf": "@IstFirma" }
Die Regeln stehen einmal zentral unter kc:rules; die Felder verweisen
mit @Name darauf.
Das macht spätere Anpassungen leichter — du pflegst die Bedingung nur an einer
Stelle, und @IstFirma ist mit weiterer Logik kombinierbar
(@IstFirma && kc.num(umsatz) > 0). Details unter Regeln.
Ausdrücke kompakt halten¶
Lange Verknüpfungen in einem einzelnen Ausdruck werden schnell
unleserlich. Zerlege sie in Regeln mit sprechenden Namen und
setze sie mit @Name zusammen — der Baukasten der Regeln stellt verschachtelte
Gruppen übersichtlich dar.
Testen¶
Schreibe die Bedingung, speichere, und prüfe sie in der Editor-Vorschau: Die Vorschau wertet Bedingungen live aus. Mit Ausgeblendete anzeigen siehst du auch Felder, die gerade unsichtbar sind — sie erscheinen ausgegraut, mit gestricheltem Rahmen und dem Vermerk bedingt sichtbar. So kannst du sie anklicken und weiterbearbeiten, ohne die Bedingung erfüllen zu müssen.

Fehlerhafte Ausdrücke meldet die Browser-Konsole („Ausdruck konnte nicht ausgewertet werden").
Limitierungen und Hinweise¶
- Serverseitige Prüfung — beim Speichern wertet der Server
kc:visibleIfundkc:requiredIfselbst aus (gleiche Semantik wie im Browser): Unsichtbare Felder werden nicht geprüft, sichtbare mit zutreffendemkc:requiredIfmüssen gefüllt sein. Schreibgeschützte Felder sind nie Pflicht. kc:clearIfInvisiblenur im Browser — das Leeren übernimmt der Renderer. Wer Daten per API oder Skript ohne das Web-Formular schreibt, muss unsichtbare Felder selbst leeren.- Versteckte Werte beim Laden — wenn ein gespeicherter Datensatz
Werte für aktuell unsichtbare Felder enthält und
kc:clearIfInvisibleaktiv ist, werden diese beim ersten Render gelöscht. Beim Laden eines Datensatzes „wandern" diese Werte also einmalig zunullund beim nächsten Submit ist die DB konsistent — semantisch genau das, was wir wollen. - Performance — Ausdrücke werden bei jedem Render neu evaluiert. Der Cache verhindert Re-Compile, aber die Auswertung selbst läuft auf jedem Tastendruck im jeweils ausgewerteten Feld. Bei einem typischen Formular mit 20 Bedingungen liegt das im Mikrosekunden-Bereich und ist nicht spürbar.
- Kein abgeschotteter Sandkasten im Browser — der Ausdruck könnte
windowoderdocumentansprechen, weilnew Functionim globalen Bereich läuft. Da nur Formular-Autoren Ausdrücke schreiben, ist das bewusst so.
Schnellreferenz¶
| Was du erreichen willst | So machst du es |
|---|---|
| Feld nur zeigen, wenn Checkbox X gesetzt ist | "kc:visibleIf": "x" |
| Feld nur zeigen, wenn Checkbox X NICHT gesetzt ist | "kc:visibleIf": "!x" |
Feld nur zeigen, wenn Auswahl A "Wert" hat |
"kc:visibleIf": "a === 'Wert'" |
| Feld zeigen bei einem von mehreren Werten | "kc:visibleIf": "typ === 'A' || typ === 'B'" |
| Feld zeigen NUR wenn beide Bedingungen wahr sind | "kc:visibleIf": "x && y" |
| Feld zeigen, wenn Zahl > 100 | "kc:visibleIf": "kc.num(betrag) > 100" |
| Pflichtfeld nur wenn sichtbar (Standard-Pattern) | beide Attribute auf denselben Ausdruck setzen |
| Wert beim Ausblenden auto-leeren | "kc:clearIfInvisible": true |
| Punkt im Feldnamen referenzieren | values["adr.land"] |
| Optional Chaining für eventuell-leere Strings | plz?.startsWith("01") |