Zum Inhalt

Makros (${…})

KCForms-Makros sind kleine Platzhalter im Format ${klasse:attribut}, die an der Render-Zeit durch dynamische Werte ersetzt werden. Sie sparen ein eigenes onLoad-Skript ein, wenn man bloß den angemeldeten Benutzer oder eine andere bekannte Größe in einem Leittext / Vorgabewert / Footer einbauen möchte.

Die Makros werden an diesen Stellen aufgelöst:

Ort Auflösung
Skripte (macros.resolve(...)) Server (MacroService)
Web-Formular (Leittexte, Titel, Tooltips …) Browser (macros.ts, Spiegel des Servers)
PDF (Leittexte, Titel, Kopf- und Fußzeilen) Server
kc:defaultValue beim Öffnen Server

Browser und Server kennen dieselben Klassen — ein im PDF aufgelöstes ${user:firstName} ergibt im Browser dasselbe.

Syntax

${klasse:attribut}            ${user:firstName}
${klasse:a:b}                 ${attachment:0:name}
${modifier|klasse:attribut}   ${upper|user:lastName}
                              ${date|now}
                              ${escape|user:lastName}

Unauflösbare Makros werden zu einem leeren String — eine Tippfehler- Klasse zerstört also nicht den ganzen Leittext.

Verfügbare Klassen

system

Makro Wert
${system:id} Umgebungs-Id aus app_settings.system.id (z. B. Prod, Dev, QS)
${system:engine} konstant server — KCForms hat keine Filler-/Portlet-Variante
${system:isServer} konstant true
${system:isFiller} konstant false
${system:isPortlet} konstant false
${system:product} konstant KCForms
${system:release} Version aus kcforms.version (Spring-Property)

session

Makro Wert
${session:id} Servlet-Session-ID (im Frontend leer)
${session:locale} Browser-Locale (de_DE, en_US, …)
${session:locale.language} Nur der Sprach-Anteil (de, en, …)
${session:remoteAddress} Client-IP (im Frontend leer)
${session:creationTime} Zeitstempel des Session-Starts (im Frontend leer)

user

Makro Wert
${user:id} Login-Name (Aliase: idUser, name)
${user:firstName} Vorname aus dem User-Profil
${user:lastName} Nachname aus dem User-Profil
${user:emailAddress} E-Mail-Adresse (Alias: email)
${user:locale} Voreingestellte Locale aus dem Profil
${user:lastLogin} ISO-Zeitstempel der letzten Anmeldung
${user:client} Mandanten-Id (sofern gepflegt)

form

Makro Wert
${form:id} Form-Id (z. B. bestellung)
${form:folder} Katalog-Ordner
${form:info.title} Titel aus dem Schema
${form:info.description} Beschreibung aus kc:description
${form:info.version} Version (V0001 etc.)
${form:info.versionName} Optionaler Versions-Name aus meta.versionName
${form:info.versionDisplay} Kombiniert: Pilot (V0001)
${form:info.shortTitle} Kurztitel aus meta.shortTitle
${form:info.author} Autor (Schema-Author bzw. meta.author)
${form:info.validFrom} Aus meta.validFrom, falls gesetzt
${form:info.validTo} Aus meta.validTo, falls gesetzt

value

${value:elementName}        Wert eines Feldes aus dem aktuellen Datensatz

Im Frontend ist das reaktiv — jeder Tastendruck im Feld aktualisiert auch alle Leittexte, die ${value:…} enthalten. Ein vorangestelltes ../ wird ignoriert (${value:../foo} = ${value:foo}).

param

${param:freigabegrenze}     Wert der Property „freigabegrenze" dieses Formulars

${param:…} liefert die Properties des Formulars (bzw. globale Properties) — dieselben Werte, die Skripte als ctx.params.<name> sehen. So lassen sich Grenzwerte, Adressen oder Hinweistexte pflegen, ohne das Formular zu ändern.

instance

Makro Wert
${instance:index} 0-basiert; -1 bei einem neuen, ungespeicherten Datensatz
${instance:index1} 1-basiert (0 bei neuem Datensatz)
${instance:isNew} true/false als String
${instance:isModified} true, sobald der Anwender getippt hat
${instance:count} Anzahl Datensätze in der aktuellen Liste; -1 wenn unbekannt
${instance:key} String-Repräsentation des Primary-Keys

attachment

Makro Wert
${attachment:count} Anzahl der Anhänge
${attachment:countVisible} Anzahl sichtbarer Anhänge
${attachment:0} Default-URL (/api/attachments/{id}/download)
${attachment:0:name} Dateiname der ersten Anlage
${attachment:0:nameWithoutExtension} Name ohne Dateiendung
${attachment:0:extension} Dateiendung in Großbuchstaben
${attachment:0:contentType} Mime-Type
${attachment:0:uuid} UUID, falls vorhanden
${attachment:<uuid>:name} UUID-basierter Lookup

document (nur PDF)

Makro Wert
${document:page} Aktuelle Seitenzahl (1-basiert) — nur sinnvoll im Footer
${document:pages} Gesamtseitenzahl

Verwendung in Kopf- und Fußzeilen, z. B.:

"kc:document": {
  "footer": "Seite ${document:page} von ${document:pages}"
}

Kopf- und Fußzeilen zeichnet KCForms erst, wenn der Inhalt fertig ist — deshalb kennt ${document:pages} die endgültige Seitenzahl. In Leittexten bleiben die beiden Makros leer. Kopf- und Fußzeilen lassen sich auch zentral als Druckvorlage pflegen.

i18n — sprachabhängige Beschriftungen

${i18n:<schlüssel>} liefert ein lokalisiertes Standard-Wort in der aktuellen Anzeige-/Dokumentsprache. So bleibt der Zahlenwert bei ${document:page}/${document:pages}, die Wörter drumherum kommen aus einem eingebauten Wörterbuch (das übliche Report-Muster: numerische Tokens + Resource-Bundle). Beispiel für einen sprachneutralen Footer:

${i18n:page} ${document:page} ${i18n:of} ${document:pages}

→ „Seite 1 von 3" (de) · „Sida 1 av 3" (sv) · „Page 1 of 3" (en).

Schlüssel de sv en
page / pages Seite / Seiten Sida / Sidor Page / Pages
of von av of
printDate / printedOn Druckdatum / gedruckt am Utskriftsdatum / utskrivet den Print date / printed on
sendDate / sentOn Versendedatum / versendet am Skickat den / skickat den Sent date / sent on
date / dateTime / time Datum / Datum-Zeit / Uhrzeit Datum / Datum-tid / Tid Date / Date-time / Time
form / author / version Formular / Autor / Version Formulär / Författare / Version Form / Author / Version
createdOn / no erstellt am / Nr. skapad den / Nr created on / No.
sheet / sheets Blatt / Blätter Blad / Blad Sheet / Sheets

Datumswerte kombinierst du mit dem locale-fähigen ${date|…}, z. B. ${i18n:printDate}: ${date(dd.MM.yyyy)|now} → „Druckdatum: 15.07.2026" / „Utskriftsdatum: 2026-07-15".

Welche Uhr gilt: now ist der Zeitpunkt auf dem Server. In welcher Zeitzone er ausgegeben wird, legt der Administrator unter System-Einstellungen → Zeitzone für Datums- und Zeitangaben fest. Ohne Einstellung gilt die Uhr des Servers — siehe Welche Uhr gilt?

Sprachquelle: Im Web-Formular folgt ${i18n:…} dem Sprach-Umschalter (Ansichtssprache). Im PDF folgt es der Render-Sprache — beim Ausdruck die UI-Sprache, bei mail-/pdf-Skripten die Skript-Sprache ctx.lang (z. B. die Empfänger-Sprache). Unbekannte, aber sinnvolle Sprachen fallen auf Deutsch zurück; ein unbekannter Schlüssel wird sichtbar als Klartext ausgegeben (Tippfehler-Hinweis).

Ebenfalls sprachabhängig im PDF: ${form:info.title} — liegt für das Formular eine Titel-Übersetzung vor, erscheint sie im PDF-Kopf in der Render-Sprache (sonst der Basistitel).

env

${env:os.name}             Aus System.getProperty("os.name")
${env:java.version}        Aus System.getProperty("java.version")
${env:java.vendor}         …

Funktioniert nur im PDF und im Skript-Binding — der Browser hat keinen Zugriff auf System-Properties und liefert für ${env:…} leer zurück. Bewusst werden nur Java-System-Properties unterstützt, keine ENV- Variablen — die enthalten oft Secrets (DB-URLs, Passwörter), die nicht versehentlich in einem Leittext landen sollen.

Modifier

Modifier kommen vor dem Klassen-Body, getrennt durch einen senkrechten Strich (|):

Modifier Wirkung
${upper|…} toUpperCase
${lower|…} toLowerCase
${escape|…} SQL-Quote: ' verdoppeln, äußere Single-Quotes setzen
${date|…} Datum als yyyy-MM-dd. Akzeptiert ISO-Strings oder das Literal now
${time|…} Zeit als HH:mm:ss
${datetime|…} yyyy-MM-dd HH:mm:ss

Eigenes Format-Pattern

Alle Datums- und Zeit-Modifier können ein eigenes Format-Pattern in Klammern tragen — die Syntax folgt dem Java SimpleDateFormat. Wer ohne Klammern aufruft, bekommt das Default-Pattern (siehe Tabelle oben).

${date(dd.MM.yyyy)|now}                                06.05.2026
${time(HH:mm)|now}                                     14:32
${datetime(yyyy/MM/dd HH:mm)|user:lastLogin}           2026/05/06 14:32
${datetime(EEEE, dd. MMMM yyyy 'um' HH:mm)|now}        Mittwoch, 06. Mai 2026 um 14:32
${format(dd.MM.yyyy)|user:lastLogin}                   06.05.2026

Wichtigste Pattern-Token im Schnellüberblick:

Token Bedeutung
yyyy Vierstelliges Jahr
yy Zweistelliges Jahr
MM Monat (zweistellig, z. B. 05)
MMM Monatsname kurz (Mai)
MMMM Monatsname lang (Mai/Januar)
dd Tag (zweistellig)
HH Stunde 0–23
hh Stunde 1–12
mm Minute
ss Sekunde
EEE Wochentag kurz (Mi)
EEEE Wochentag lang (Mittwoch)
'…' Literaler Text in einfachen Hochkommas

Innerhalb der Klammern darf jedes Zeichen außer ) stehen. Wer eine schließende Klammer im Format-String braucht, splittet das Makro und ergänzt die Klammer als reinen Literal-Text drumherum.

Beispiele für reine Modifier ohne Format-Argument:

${upper|user:lastName}                    KEHRMANN
${escape|user:lastName}                   'Kehrmann'  (für SQL)
${date|now}                               2026-05-03
${datetime|value:erstelltAm}              2026-05-03 14:30:00

Wo verwenden?

Macros werden überall dort ersetzt, wo der Renderer einen "präsen­tierten" String anfasst — Eingabe-Werte (also der Inhalt eines Inputs) bleiben absichtlich unangetastet, sonst könnte man ${...} nie als wirklichen Wert eingeben.

Schema-Feld Frontend PDF Beim Öffnen
title (Field-Label) ✓ ✓ —
description (Section) ✓ — —
kc:text.content ✓ ✓ —
kc:link.text / kc:link.url ✓ — —
kc:button.label ✓ — —
kc:section.title ✓ — —
Form-title (Header) ✓ —
kc:document.title/author/footer — ✓ —
kc:pages.*.title — ✓ —
kc:defaultValue — — ✓

Skripte

Im Skript steht macros als Top-Level-Binding bereit:

var begruessung = macros.resolve("Hallo ${user:firstName}!");
ctx.form.greeting = begruessung;

// Debug-Helper — zeigt den aktuellen MacroContext
log.info(JSON.stringify(macros.debug(), null, 2));

Im Skript sieht der Resolver dieselben Werte, die der Renderer auch sehen würde. Wer dynamisch komponiert (z. B. eine Mail-Body-Template), fährt damit gut.

Demo-Formular

Das Beispielformular Makros · Live-Auflösung (macros-demo, installierbar unter System-Administration → Formular-Bausteine → Beispiele) zeigt alle Makros aufgelöst. Die Eingabefelder sind über kc:defaultValue vorbelegt — vorname mit ${user:firstName}, nachname mit ${user:lastName}, referenz mit REF-${user:id}. Beim Drucken läuft auch die Fußzeile Seite ${document:page} von ${document:pages} mit.