Zum Inhalt

Validierung & Formate

Damit keine unbrauchbaren Daten im System landen, prüft KCForms jede Eingabe, bevor sie gespeichert wird. Als Formular-Autor legst du fest, was geprüft wird — auf drei Wegen:

  • Regeln am Feld — Pflicht, Typ, Länge, erlaubte Auswahlwerte, Muster, Datumsformat und Datumsvergleiche. Das deckt die meisten Fälle ab.
  • Feld-Validatoren (kc:validator) — freigegebene Prüffunktionen aus Bibliotheken (IBAN, USt-IdNr. …), live im Browser und verbindlich auf dem Server.
  • Ein onValidate-Skript — für Geschäftsregeln, die sich mit den Regeln am Feld nicht ausdrücken lassen, etwa „bei Rabatt ist eine Begründung nötig".

Zusammenklicken reicht — das JSON ist zum Nachschauen da

Pflichtfelder, Längen, Auswahllisten, Muster, Zahlenformate und Datumsvergleiche richtest du vollständig im Formular-Editor ein, ohne eine Zeile zu tippen. Die eingeklappten Kästen „Hinter den Kulissen" auf dieser Seite zeigen, was der Editor dabei in das Formular schreibt. Aufklappen lohnt sich, wenn du wissen willst, warum eine Prüfung anschlägt — oder warum sie ausbleibt — und wenn du ein Formular exportieren und in einer anderen Umgebung wieder einspielen willst. Nur die eigenen Geschäftsregeln im Abschnitt onValidate-Skript verlangen wirklich getippten Code.

Geprüft wird nicht erst beim Speichern: Schon wenn der Anwender ein Feld verlässt, meldet das Formular einen falschen Wert. Der Pflicht-Check bleibt dabei außen vor — sonst wäre jedes noch leere Feld sofort rot. Ein Pflichtfeld leer zu lassen, ist eben nicht dasselbe, wie es leer zu speichern: Die Live-Prüfung warnt nur, wenn ein eingegebener Wert falsch ist.

Im Formular-Editor

Sofort serverseitig validieren (beim Verlassen) im Reiter Sichtbarkeit der Feld-Eigenschaften setzt kc:serverValidateOnChange. Dann läuft schon beim Verlassen des Feldes die vollständige Prüfung inklusive onValidate, nicht nur die dieses einen Feldes.

Regeln, die du am Feld einstellst

Pflichtfelder

Ein Feld als Pflichtfeld zu markieren, heißt: Der Server nimmt den Datensatz ohne Wert nicht an. Dynamische Pflicht — „nur nötig, wenn …" — legst du über kc:requiredIf fest; auch die prüft der Server.

Nicht geprüft werden:

  • unsichtbare Felder (kc:visible: false oder kc:visibleIf falsy),
  • schreibgeschützte Felder (kc:readonly) — sie füllt das System.
Hinter den Kulissen: Pflichtfelder im Schema
{
  "required": ["name", "email"],
  "properties": {
    "name":  { "type": "string", "title": "Name" },
    "email": { "type": "string", "title": "E-Mail", "format": "email" }
  }
}

JSON-Schema-Standard: Die Liste required neben properties nennt die Pflichtfelder. Alternativ kc:required: true direkt am Feld — gleiche Wirkung.

Ankreuzfelder: beantwortet oder zugestimmt?

Bei einem Ankreuzfeld gibt es zwei verschiedene Ansprüche, und Pflichtfeld allein meint den schwächeren:

Einstellung Erfüllt durch Gedacht für
Pflichtfeld Haken oder kein Haken — nur „nie beantwortet" fehlt „Newsletter? ja/nein"
Zustimmung erzwingen (kc:requiredTrue) nur den gesetzten Haken „AGB gelesen", „Richtigkeit bestätigt"

Der Grund für die Trennung: Bei einer Frage wie „Newsletter abonnieren?" ist „nein" eine Antwort — dort darf der Satz ohne Haken gespeichert werden. Bei einer Bestätigung darf er das nicht. Welcher Fall vorliegt, weiß nur du als Designer, deshalb sind es zwei Einstellungen und nicht eine.

„Zustimmung erzwingen" schließt die Pflicht ein — du brauchst nicht beides anzuklicken. Ein noch unbeantwortetes Feld meldet „Pflichtfeld", ein abgewähltes „Bitte bestätigen".

Wenn du ein Bestätigungs-Häkchen aus einer älteren Fassung hast

Dort stand vermutlich nur Pflichtfeld — und das ließ sich mit einem Klick auf das Häkchen und zurück erfüllen. Setze bei solchen Feldern zusätzlich Zustimmung erzwingen; die Einstellung ist absichtlich opt-in, damit bestehende Ja/Nein-Felder unverändert weiterlaufen.

Welcher Typ zugelassen ist

type Akzeptiert
"string" jeder Text
"number" eine Zahl, auch mit Dezimalkomma oder Tausenderpunkt ("1.234,56", "1,234.56")
"integer" eine ganze Zahl; Nachkommastellen werden abgewiesen (siehe unten)
"boolean" true / false
"array" Liste; bei kc:childTable siehe Detail-Tabellen

Wie lang ein Text sein darf

Schlüssel Wirkung
kc:maxLength höchstens so viele Zeichen — bestimmt auch die Spaltenbreite (siehe unten)
kc:minLength mindestens so viele Zeichen (leere, nicht-pflichtige Felder sind erlaubt)

Feste Auswahl: nur bestimmte Werte (enum)

Ein Feld lässt sich auf eine geschlossene Werteliste einschränken. Werte außerhalb der Liste lehnt der Server ab. Im Schema sind das drei Zeilen:

"prio": {
  "type": "string", "title": "Priorität",
  "enum": ["LOW", "MEDIUM", "HIGH"]
}

Für Auswahllisten mit lesbarem Anzeigetext siehe Lookups.

Datum und Uhrzeit

Datumsfelder prüft KCForms streng — Muster und Kalender:

Format Muster Beispiel für einen Fehler
date JJJJ-MM-TT 2026-02-30
date-time JJJJ-MM-TT HH:mm (auch mit T, Sekunden, Zeitzone) 2026-13-01 10:00

Gespeichert wird immer im ISO-Format; die Anzeige steuert kc:dateFormat bzw. kc:formDateFormat. Der Datums-Picker kennt Mindest- und Höchstdatum (kc:minDate, kc:maxDate), Kalenderwochen und weitere Optionen.

format: "email" erzeugt ein E-Mail-Eingabefeld, prüft auf dem Server aber nicht streng — für strenge Prüfung ein pattern ergänzen.

Zwei Datumsfelder vergleichen

Ein Datumsfeld kannst du gegen andere Datumsfelder prüfen lassen — der klassische Fall ist „Ende nicht vor Beginn". Am späteren Feld legst du dazu eine oder mehrere Vergleichsregeln an, jede mit eigener Fehlermeldung.

Hinter den Kulissen: Datumsvergleich (kc:dateCompare)
"reiseende": {
  "type": "string", "format": "date", "title": "Reiseende",
  "kc:dateCompare": {
    "enabled": true,
    "rules": [
      { "op": "ge", "other": "reisebeginn", "message": "Das Ende darf nicht vor dem Beginn liegen." }
    ]
  }
}

op: lt (vor), le (vor oder gleich), gt (nach), ge (nach oder gleich), eq, ne. Mehrere Regeln sind möglich.

Eingaben gegen ein Muster prüfen

Muss ein Wert einer festen Form folgen — fünfstellige PLZ, Aktenzeichen, IBAN-Schreibweise —, hinterlegst du am Feld ein Muster: einen regulären Ausdruck, dazu die Fehlermeldung, die der Anwender zu sehen bekommt, und ob das ganze Feld passen oder das Muster nur enthalten sein muss.

Hinter den Kulissen: Muster am Beispiel einer IBAN
"iban": {
  "type": "string", "title": "IBAN",
  "pattern":           "^[A-Z]{2}\\d{2}[A-Z0-9]+$",
  "kc:patternMode":    "match",
  "kc:patternMessage": "Bitte gültige IBAN eintragen."
}

JSON-Schema kennt pattern als regulären Ausdruck; KCForms ergänzt Modus und Fehlertext.

Schlüssel Wert Bedeutung
pattern regulärer Ausdruck (Java-Syntax) das Muster
kc:patternMode "match" (Standard) das ganze Feld muss passen
"contain" das Feld muss das Muster enthalten
kc:patternMessage Text Fehlermeldung unter dem Feld

Muster werden live beim Verlassen und beim Speichern geprüft. Ein leeres, nicht-pflichtiges Feld scheitert nie am Muster.

Zwei weitere typische Fälle: eine PLZ, die vollständig aus fünf Ziffern bestehen muss (match), und eine Telefonnummer, in der irgendwo mindestens drei Ziffern vorkommen müssen (contain).

Hinter den Kulissen: PLZ (match) und Telefon (contain)
"plz": {
  "type": "string", "title": "PLZ",
  "pattern": "^\\d{5}$",
  "kc:patternMessage": "Bitte 5-stellige PLZ."
},
"telefon": {
  "type": "string", "title": "Telefon",
  "pattern": "\\d{3,}",
  "kc:patternMode": "contain",
  "kc:patternMessage": "Bitte mindestens 3 Ziffern."
}

Fertige Prüfungen

Für IBAN, BIC, USt-IdNr. und Ähnliches gibt es Feld-Validatoren mit echter Prüfziffer-Kontrolle — ein Muster prüft nur die Form.

Nachkommastellen bei Zahlen (kc:decimals)

Die Nachkommastellen eines Zahlenfeldes legen zweierlei fest: wie der Wert angezeigt wird und wie genau die Datenbank-Spalte (DECIMAL(18, n)) ihn aufbewahrt. Im Schema ist das ein einzelner Schlüssel:

"betrag": { "type": "number", "title": "Betrag (€)", "kc:decimals": 2 }
kc:decimals Spalte Anzeige
0 DECIMAL(18, 0) 1234
2 DECIMAL(18, 2) 1.234,56
(fehlt) DECIMAL(18, 4) wie eingegeben

Erlaubt sind 0 bis 10. Beim Verlassen des Feldes formatiert das Formular den Wert mit der gewählten Anzahl Nachkommastellen. Tausender- und Dezimaltrenner, Präfix und Suffix steuern kc:thousandSeparator, kc:decimalSeparator, kc:numberPrefix und kc:numberSuffix.

Bei Berechnungsfeldern genügt eine Angabe

Auch der Formel-Editor eines Berechnungsfeldes fragt nach Nachkommastellen. Du musst die Zahl nur an einer der beiden Stellen eintragen — steht am Feld selbst keine, gilt die aus der Formel. Steht sie an beiden, gewinnt die Angabe am Feld: sie beschreibt die Anzeige, die Formel-Angabe zuerst die Rechengenauigkeit.

Ist nirgends eine Angabe hinterlegt, zeigt das Formular so viele Stellen, wie der Wert selbst mitbringt — ein gespeicherter Betrag 238,50 erscheint also als 238,50 und nicht als 238,5. Im Ausdruck gelten in diesem Fall zwei Stellen; wer beides sicher gleich haben will, trägt die Nachkommastellen ausdrücklich ein.

Zahlenbereich (minimum / maximum)

Bei einem Zahlenfeld kannst du im Reiter Element ein Minimum und ein Maximum eintragen. Beide Grenzen sind einschließend: Bei 0 bis 100 sind 0 und 100 erlaubt, −1 und 100,01 nicht.

"prozent": { "type": "number", "title": "Anteil (%)",
             "kc:decimals": 2, "minimum": 0, "maximum": 100 }

Der erlaubte Bereich steht als Hinweis unter dem Feld („Erlaubt: 0 bis 100“) — der Anwender muss also nicht erst dagegenlaufen, um ihn zu erfahren. Trägst du nur eine der beiden Grenzen ein, nennt der Hinweis nur diese („Erlaubt: mindestens 18“). Geprüft wird beim Verlassen des Feldes und beim Speichern; ein Verstoß markiert das Feld rot und blockiert das Speichern wie jeder andere fachliche Fehler. Ein Entwurf lässt sich trotzdem zwischenspeichern, falls das Formular das erlaubt — der Wert passt ja in die Spalte, er gefällt nur nicht.

Vor dem Stand vom 05.10.2026 hatten diese beiden Felder keine Wirkung

Der Dialog schrieb minimum und maximum seit je ins Schema, und gelesen hat sie niemand: weder die Prüfung auf dem Server noch das Formular. Wer sie in einem älteren Formular eingetragen hat, bekommt sie jetzt nachträglich scharf. Schau bei Bestandsformularen also einmal nach, ob die dort hinterlegten Grenzen noch stimmen — sonst beanstandet das Formular plötzlich Eingaben, die es jahrelang angenommen hat.

Ganzzahlfelder nehmen keine Nachkommastellen

Ein Feld vom Typ integer liegt in einer Ganzzahl-Spalte. Trägt jemand dort 5,7 ein, meldet das Feld „Bitte eine ganze Zahl ohne Nachkommastellen eingeben". 5 und 5,0 gehen durch — 5,0 ist eine ganze Zahl, auch wenn sie eine Null hinter dem Komma hingeschrieben bekommen hat.

Der Fehler ist hart und blockiert das Speichern auch im Entwurfsmodus. Das ist Absicht: Die Alternativen wären, den Wert beim Speichern stillschweigend zu runden — dann stünde eine andere Zahl im Datensatz als die eingegebene — oder ihn fallen zu lassen. Beides ist schlechter als ein Hinweis, den man in zwei Sekunden abstellt.

Vor dem Stand vom 05.10.2026 ging der Wert verloren

5,7 galt bis dahin als gültige Zahl. Das Speichern meldete Erfolg, und in der Spalte stand nichts — kein Hinweis, kein Eintrag im Protokoll. Dasselbe passierte bei 1.000,50 in einem Zahlenfeld mit Nachkommastellen, also einem Betrag mit deutschem Tausenderpunkt. Beides kommt jetzt an bzw. wird gemeldet. Wenn in einem Bestandsformular Zahlenfelder unerklärlich leer sind, ist das die wahrscheinliche Ursache.

Die technische Obergrenze

Unabhängig von minimum/maximum fasst die Spalte nur eine begrenzte Zahl. Wie viel, hängt an den Nachkommastellen ab: Beide teilen sich einen Vorrat von 18 Stellen.

Nachkommastellen Stellen vor dem Komma größter Wert
0 18 999999999999999999
2 16 9999999999999999,99
4 (Vorgabe) 14 99999999999999,9999
Ganzzahl (integer) 19 9223372036854775807

Wird diese Grenze überschritten, meldet das Feld „Die Zahl ist zu groß — höchstens 14 Stellen vor dem Komma (aktuell 15)“. Dieser Fehler ist hart: Er blockiert das Speichern auch im Entwurfsmodus, weil die Zahl physikalisch nicht in die Spalte passt. Diese Grenze steht bewusst nicht als Hinweis unter dem Feld — sie liegt so hoch, dass niemand sie im Alltag berührt, und würde unter jedem Zahlenfeld nur Störung sein.

Die beiden Richtungen verhalten sich verschieden

Zu viele Stellen nach dem Komma werden gerundet — aus 1,23456789 wird in einem Feld mit vier Stellen 1,2346, ohne Meldung. Zu viele Stellen vor dem Komma werden abgewiesen. Der Grund ist, dass Runden eine Entscheidung ist, die man treffen kann, ohne den Anwender zu fragen; das Weglassen einer Führungsstelle wäre dagegen eine andere Zahl.

Vorsicht beim Grenzfall: Das Runden kann den Überlauf selbst erzeugen. 99999999999999,99995 hat 14 Stellen vor dem Komma und ist damit scheinbar in Ordnung — gerundet auf vier Nachkommastellen werden daraus 100000000000000,0000, also 15. Das Formular rechnet das mit und beanstandet die Eingabe.

Mehrfachauswahl: wie viel passt hinein?

Die Werte einer Mehrfachauswahl — Ankreuzgruppe, Mehrfach-Auswahlliste oder freie Stichwortliste — liegen zusammen als Liste in einer Spalte. Wie viel dort hineinpasst, zeigt die Kopfzeile des Feld-Dialogs an: Typ: multicheck / string(500).

Wird mehr gewählt, als hineinpasst, meldet das Feld „Die Auswahl ist zu umfangreich — sie braucht 1.161 Zeichen, das Feld fasst 500". Der Fehler ist hart und blockiert das Speichern auch im Entwurfsmodus, weil die Auswahl physisch nicht in die Spalte passt.

Wie viel Platz entsteht, hängt davon ab, was das Feld weiß:

Feld Platz
Feste Optionsliste so viel, wie alle Optionen zusammen brauchen — mindestens 500 Zeichen
Freie Stichwortliste 500 Zeichen
Mit eigener Höchstlänge (kc:maxLength) genau diese — ab 4000 wird daraus unbegrenzter Text

Bei einer festen Optionsliste kann der Platz also gar nicht ausgehen: Er ist so bemessen, dass alle Optionen gleichzeitig angehakt sein dürfen. Eng wird es nur bei frei eingetippten Stichworten. Brauchst du dort mehr, trage im Reiter Erweitert eine Höchstlänge ein.

Vor dem Stand vom 06.10.2026 gab es hier keine Prüfung

Eine zu große Auswahl lief ungebremst in die Datenbank und kam als technischer Abbruch zurück, nicht als Feldfehler. Gespeichert wurde nichts.

Was in einer Detail-Tabelle geprüft wird

Seit dem Stand vom 07.10.2026 prüft der Server jede Zelle einer Detail-Tabelle so wie ein gewöhnliches Feld: Typ, Länge, Zahlenbereich und Datumsform. Die Meldung nennt Zeile und Spalte:

Zeile 2, „Datum“: Bitte ein gültiges Datum eingeben (TT.MM.JJJJ)

Die Grenzen stammen aus der Spalte dieser Zelle — die ist eigenständig und etwas schmaler bemessen als die eines Hauptfeldes. Ohne eigene Angabe fasst eine Textspalte in einer Detail-Tabelle 255 Zeichen.

Diese Befunde sind hart: Sie blockieren das Speichern auch im Entwurfsmodus, weil der Wert sonst physisch nicht in die Spalte passt.

Vor dem Stand vom 07.10.2026 gab es diese Prüfung nicht

Dieselbe Eingabe verhielt sich im Hauptformular und in einer Tabellenzelle völlig verschieden:

Eingabe Hauptfeld Detail-Zelle (vorher)
Datum 32.12.2012 abgelehnt still als 2032-12-20 gespeichert
Datum morgen abgelehnt technischer Abbruch
Zahl viel abgelehnt gespeichert — Zelle blieb leer
600 Zeichen in einer 255er-Spalte abgelehnt technischer Abbruch

Der erste Fall war der tückischste: Aus einem Datum, das es nicht gibt, wurde ein anderes, plausibel aussehendes. Wenn in älteren Datensätzen Detail-Zellen unerklärlich leer sind oder ein Datum nicht zur Eingabe passt, ist das die wahrscheinliche Ursache.

Nicht geprüft werden in Zellen enum und Muster (kc:pattern). Das sind fachliche Regeln und keine Speichergrenzen — sie können nichts zerstören.

Textlänge und Spaltenbreite (kc:maxLength)

Die zulässige Textlänge bestimmt zugleich, wie breit die Spalte in der Datenbank angelegt wird:

"strasse": { "type": "string", "title": "Straße", "kc:maxLength": 80 }
kc:maxLength Spalte
(fehlt) VARCHAR(255)
bis 4 000 VARCHAR(n)
über 4 000 TEXT

Textbereiche (kc:widget: "textarea") werden immer als TEXT gespeichert. Eine spätere Erhöhung verbreitert eine bestehende Spalte nicht automatisch — siehe Datenmodell.

Die Grenze greift schon beim Tippen

Das Feld nimmt nicht mehr als kc:maxLength Zeichen an — beim Tippen wie beim Einfügen, ein- und mehrzeilig und auch in Detail-Tabellen. Vorher ließ sich beliebig viel eingeben und der Hinweis kam erst beim Speichern; bei einem versehentlich eingefügten Roman war das eine unangenehme Überraschung.

Damit niemand rätselt, warum das Feld plötzlich nichts mehr annimmt, blendet sich ab 90 % der Grenze automatisch der Zeichenzähler ein („487 / 500"), auch ohne kc:showCharCounter — er wird gelb und bei Erreichen der Grenze rot.

Bestehende Daten bleiben unangetastet: Ein Datensatz, der die Grenze schon überschreitet (weil sie später gesenkt wurde), wird weiterhin vollständig angezeigt und nicht stillschweigend gekürzt. Beim Speichern meldet ihn die Validierung wie bisher.

Auch ohne kc:maxLength ist die Spalte begrenzt

Das ist die häufigere Stolperfalle: Ein gewöhnliches Textfeld ohne kc:maxLength bekommt VARCHAR(255), ein format: "email" sogar nur VARCHAR(120), und eine Auswahlliste richtet sich nach ihrem längsten Eintrag. Wer dort mehr hineinschreibt, bekam früher keine Feldmeldung, sondern die Meldung des Datenbanktreibers („Data too long for column") als technischen Fehler.

Die Validierung prüft deshalb gegen die tatsächliche Kapazität der Spalte — auch dann, wenn im Schema gar keine Länge steht. Wer mehr Platz braucht, setzt kc:maxLength ausdrücklich; über 4 000 entsteht ohnehin TEXT und die Zeichenzahl ist dann praktisch offen.

Die Prüfung läuft ein zweites Mal nach den Skripten, unmittelbar vor dem Schreiben. Ein onValidate- oder onBeforeSave-Hook, der selbst einen zu langen Wert setzt, wird also ebenfalls abgefangen — mit Feldnamen statt Stacktrace. Nicht abgedeckt ist bewusst rohes db.update(...) aus einem Skript: das ist die SQL des Autors, dort gehört die Treibermeldung hin.

Was als ein Zeichen zählt

Gezählt wird seit dem Stand vom 07.10.2026 so, wie die Datenbank zählt: in Zeichen (Unicode-Codepunkten), nicht in internen Speichereinheiten. Ein Emoji ist damit ein Zeichen — in ein Feld mit Höchstlänge 10 passen zehn davon.

Vorher zählten Emoji doppelt

Bis dahin meldete ein Feld mit Höchstlänge 300 bei 300 Emoji „Höchstens 300 Zeichen erlaubt (aktuell 600)“ — obwohl die Spalte genau diese 300 aufgenommen hätte. Das Feld hielt für solche Zeichen also die halbe zugesagte Menge, und die genannte Zahl stand auf keinem Bildschirm. Für gewöhnlichen Text ändert sich nichts: Dort waren beide Zählweisen immer gleich.

Wo die Zählung trotzdem von der Anschauung abweicht

Manche Emoji bestehen aus mehreren Zeichen, die zu einem Bild zusammengesetzt werden — die Familie ‍‍ zählt fünf. Das ist kein Versehen: Maßgeblich ist, was die Spalte zählt, und die zählt ebenfalls fünf. Würde das Formular hier anders rechnen als die Datenbank, wäre wieder eine der beiden Zahlen falsch.

Eigene Regeln im Skript (onValidate)

Was das Schema nicht ausdrücken kann, gehört ins Skript — typisch feldübergreifende Regeln:

// onValidate
if (kc.num(ctx.form.rabattProzent) > 0 && kc.isEmpty(ctx.form.kommentar)) {
  ctx.addError('kommentar', 'Bei Rabatt > 0 ist eine Begründung erforderlich.');
}

// Bestelldatum nicht in der Zukunft
var heute = new Date().format('yyyy-MM-dd');
if (ctx.form.bestelldatum && ctx.form.bestelldatum > heute) {
  ctx.addError('bestelldatum', 'Das Bestelldatum darf nicht in der Zukunft liegen.');
}

ctx.addError(feld, text) sammelt Fehler; das Formular zeigt sie am jeweiligen Feld und im Fehler-Banner. Mehr zu den Skript-Hooks: Lifecycle.

Speichern trotz Fehlern

Zwei Schalter in den Formular-Eigenschaften → Erweiterte Einstellungen:

Schalter Wirkung
Speichern mit Fehlern erlauben (allowSaveWithErrors) der Datensatz wird trotz Prüffehlern gespeichert — für Entwürfe
Absenden mit Fehlern erlauben (allowSubmitWithErrors) zusätzlich läuft onSubmit (Mails, Folgeaktionen) trotz Fehlern; nur zusammen mit dem ersten Schalter sinnvoll

Was der Anwender von einem Fehler mitbekommt

Schlägt das Speichern an einer Prüfung fehl, passieren drei Dinge:

  • Oben erscheint eine Meldung mit der Anzahl der offenen Felder und dem ersten davon im Klartext — dort, wo auch der Speichern-Knopf sitzt. Bei einem langen Formular sähe man einen Hinweis am Fuß nämlich nie, und der Klick würde folgenlos wirken.
  • Die Maske springt zum ersten betroffenen Feld und setzt den Schreibcursor hinein. Liegt es auf einer anderen Seite eines mehrseitigen Formulars, wechselt die Ansicht mit.
  • Jedes betroffene Feld wird rot markiert — Rahmen bei Text-, Zahl-, Datums-, Auswahl- und Währungsfeldern, ein roter Ring bei Ankreuzfeldern (die malt der Browser selbst, ein Rahmen wäre dort unsichtbar). Darunter steht die Begründung.

Ein einmal gemeldeter Pflicht-Hinweis bleibt stehen, solange das Feld leer ist. Ihn kurz anzuklicken oder etwas zu tippen und wieder zu löschen lässt ihn also nicht verschwinden — er geht erst, wenn wirklich etwas drinsteht.

Zwei Extras für den Formular-Designer

Mit kc:showErrorsProminently bekommst du zusätzlich ein aufklappbares Fehler-Verzeichnis oben im Formular, durch das man klicken kann; mit kc:showSubmitErrorModal einen Dialog beim Speichern. Beide sind optional — Meldung, Sprung und rote Markierung gibt es immer.

Wo geprüft wird

Alle Prüfungen laufen am Ende auf dem Server — auch die, die schon im Browser gemeldet werden. Sie lassen sich also nicht dadurch umgehen, dass jemand das Formular anders bedient als vorgesehen. Intern sortiert KCForms die Prüfungen in drei Schichten und ruft je nach Auslöser — Knopf Validieren, Speichern oder Verlassen eines Feldes — unterschiedlich viel davon auf.

Hinter den Kulissen: die drei Prüf-Schichten und ihre Auslöser

Validierung passiert in KCForms in drei Schichten:

  1. Schema-Prüfung (Server) — automatisch aus dem Schema: Pflicht, Typ, Länge, Zahlenbereich, Auswahlwerte, Muster, Datumsformat, Datumsvergleich. Berücksichtigt kc:visibleIf und kc:requiredIf.
  2. onValidate-Skript — eigene Geschäftsregeln, die das Schema nicht ausdrücken kann.
  3. Feld-Validatoren (kc:validator) — freigegebene Prüffunktionen aus Bibliotheken (IBAN, USt-IdNr. …), live im Browser und verbindlich auf dem Server.

Dazu kommen Live-Prüfungen beim Verlassen eines Feldes — ohne Pflicht-Check, sonst wäre jedes noch leere Feld sofort rot.

Weil diese Prüfung Pflichtfehler gar nicht kennt, darf sie einen bereits gemeldeten auch nicht löschen: Ein Pflicht-Hinweis überlebt das Verlassen des Feldes, solange es leer bleibt. Sonst hätte ein Klick ins Feld gereicht, um die Markierung loszuwerden — und das Speichern wäre danach trotzdem fehlgeschlagen.

Welcher Auslöser welchen Endpunkt anspricht:

Auslöser Endpunkt Was wird geprüft?
Knopf Validieren POST /api/forms/{id}/validate Schema-Prüfung (inkl. Pflicht), onValidate, Feld-Validatoren
Speichern POST /api/forms/{id}/submit dasselbe, danach Speichern (siehe Reihenfolge)
Feld verlassen POST /api/forms/{id}/fieldChange Schema-Prüfung nur dieses Feldes, ohne Pflicht-Check; läuft zusammen mit onFieldChange
Feld verlassen mit kc:serverValidateOnChange: true POST /api/forms/{id}/validate vollständige Prüfung inkl. onValidate; Fehler erscheinen direkt am Feld

Reihenfolge beim Speichern

flowchart TB
    A["Speichern"] --> B["1 · Schema-Prüfung<br/>Pflicht, Typ, Länge, Zahlenbereich,<br/>enum, Muster, Datum, Datumsvergleich"]
    B --> C["2 · onValidate-Skript"]
    C --> D["3 · Feld-Validatoren (kc:validator)"]
    D --> E{"Fehler?"}
    E -- "ja (und Speichern mit Fehlern aus)" --> F["Antwort mit Fehlern"]
    E -- "nein" --> G["4 · onBeforeSave<br/>(kann abbrechen)"]
    G --> H["5 · Speichern<br/>form_&lt;id&gt; + Detail-Tabellen"]
    H --> I["6 · onSubmit<br/>Mail, PDF, Dateien"]
    I --> J["7 · onAfterSave"]
    J --> K["Antwort an das Formular"]

Der Knopf Validieren führt nur die Schritte 1–3 aus — ohne Speichern und ohne onSubmit.

Stolperfallen

  • format: "date" mit pattern: "dd.MM.yyyy" scheitert: Gespeichert und geprüft wird ISO (JJJJ-MM-TT). Das Anzeigeformat steuert kc:dateFormat.
  • Backslashes in JSON verdoppeln: \d schreibt man \\d.
  • Feldübergreifende Regeln kann das Schema nicht ausdrücken — dafür gibt es kc:requiredIf, kc:dateCompare und onValidate.
  • Pflicht über eine @Regel: Die Server-Prüfung löst @Regeln nicht auf, siehe Regeln.
  • Prüfung findet zu wenig? Unter System-Administration → Betrieb & Überwachung → Log-Konfiguration den Logger com.kcforms.forms auf DEBUG stellen — ohne Neustart.