view — Dialoge¶
Mit view zeigt ein Skript Dialoge im Formular an — modal oder als
Hinweis-Leiste: Meldungen, Bestätigungen, Fragen mit eigenen Antworten.
Die Dialog-Typen¶
| Objekt | Zweck |
|---|---|
view.Message |
Hinweis-/Info-Box, ohne oder mit OK-Knopf |
view.Question |
Frage mit beliebigen Antworten |
view.Link |
anklickbarer Link als Hinweis, z. B. auf eine erzeugte Datei |
view.Download |
modaler Dialog mit Titel und Download-Schaltfläche |
Alle vier funktionieren gleich: Du baust ein Objekt mit new und gibst es an
view.add(…). Alle Dialoge eines Skript-Laufs sammelt KCForms und zeigt sie
nach dem Lauf im Formular an.
view.Link und view.Download akzeptieren nur Adressen innerhalb von KCForms
(beginnend mit /) — typisch eine Download-Adresse aus
pdf/delivery:
var url = pdf.render().deliver('antrag.pdf');
// dezenter Hinweis mit Link
view.add(new view.Link(url, 'Antrag als PDF öffnen'));
// oder prominent, mit Titel und Schaltfläche
view.add(new view.Download(url, 'Antrag herunterladen', 'Dokument erzeugt'));
Frühere Schreibweise: view.embedLink / view.embedDownload
Vor dem Stand vom 26.09.2026 hießen die beiden view.embedLink(url, text) und
view.embedDownload(url, text [, titel]) — zwei Verben neben zwei
Substantiven. Das embed-Präfix stammte aus der Kompatibilität zu einem
übernommenen Skript-Dialekt.
Die alten Namen funktionieren unverändert weiter und erzeugen exakt denselben Dialog — beide Wege gehen durch dieselbe Stelle im Code, ein Test hält das fest. Bestehende Formulare müssen also nicht angefasst werden; für neue Skripte ist die Objekt-Schreibweise die empfohlene.
view.embedScript(code) gibt es nur, damit übernommene Skripte nicht
abbrechen: Der Aufruf wird protokolliert, der Code aber nicht
ausgeführt.
view.Message — Info-Boxen¶
Drei Konstruktoren:
new view.Message("Daten gespeichert.");
new view.Message("Daten gespeichert.", "Erfolg");
new view.Message("html:<b>Wichtig</b>", "Hinweis", {
modal: true, closable: true, okButton: true
});
| Property | Typ | Wirkung |
|---|---|---|
text |
String | Body — html:-Prefix → HTML, sonst Plain |
caption |
String | Titel |
modal |
Boolean | Backdrop, blockiert Interaktion |
closable |
Boolean | Schließen-X oben rechts |
okButton |
Boolean | OK-Knopf anzeigen |
color |
String | semantische Farbe — "red", "green", … |
styleClass |
String | freie CSS-Klasse |
iconName |
String | Symbol |
Setzbar entweder über die Optionen-Map im 3. Konstruktor-Argument oder per Property-Zuweisung:
var m = new view.Message("Bitte wählen Sie eine Option.");
m.modal = true;
m.color = "red";
m.okButton = true;
view.add(m);
html:-Prefix¶
Beginnt der text mit html:, wird der Rest als HTML angezeigt. Ohne
Präfix ist der Inhalt reiner Text; Zeilenumbrüche bleiben erhalten.
Eingaben der Anwender trotzdem umwandeln
Seit dem Stand vom 18.10.2026 säubert KCForms html:-Texte vor der Anzeige mit
derselben Regel wie Leittexte: Skripte, Event-Handler, eingebettete
Seiten und javascript:-Links fallen weg; Formatierung, Listen und
gewöhnliche Links bleiben. Werte, die Anwender eingegeben haben, baust du
trotzdem nur umgewandelt ein (<, >, &, siehe
Beispiel 14) — sonst kann jemand eigene
Formatierung oder einen Link in deinen Dialog setzen.
view.Question — Fragen mit Antworten¶
Eine Frage hat einen Body, einen Titel und eine Liste Antworten mit eigenen Callbacks:
var q = new view.Question("Wirklich speichern?", {
caption: "Speichern",
modal: true
});
q.add(new q.Answer("yes", "Ja", "antwortJa")); // String → Hook
q.add(new q.Answer("no", "Nein", function() { log.info("Nein geklickt"); }));
q.defaultAnswer = "yes";
view.add(q);
Vier Vorbelegungen — OK / YES / NO / CANCEL¶
Jede Question hat fertige Antwort-Instanzen, denen man nur den
Callback geben muss:
var q = new view.Question("Schließen?");
var yes = q.YES; yes.callback = function() { ctx.requestClose(); };
var no = q.NO;
q.add(yes);
q.add(no);
view.add(q);
| Antwort | id | label |
|---|---|---|
q.OK |
"ok" |
„OK" |
q.YES |
"yes" |
„Ja" |
q.NO |
"no" |
„Nein" |
q.CANCEL |
"cancel" |
„Abbrechen" |
Die Vorbelegungen sind per Question-Instanz — wenn du in einem
Skript zwei Fragen mit jeweils eigenem q.YES baust, sind das zwei
unabhängige Antwort-Instanzen. Kein versehentliches Sharing.
Callback-Varianten¶
Für jeden Answer.callback gibt es drei Möglichkeiten. Wichtig: Wenn der
Anwender klickt, ist das Skript, das die Frage gestellt hat, längst
beendet.
| Callback ist … | Was passiert beim Klick? |
|---|---|
| JS-Funktion | Funktion wird sofort beim view.add(...) ausgeführt — nicht erst beim Klick |
| String | Name eines Hooks; beim Klick ruft das Formular diesen Hook mit dem aktuellen Stand der Felder auf |
null |
Klick dismissed nur den Dialog, kein Roundtrip |
Klassisches Pattern: alles, was nach dem Klick passieren soll, in einen eigenen Hook packen und dort als Hook-Name eintragen:
// onSubmit-Hook
var q = new view.Question("Möchten Sie eine Bestätigung per Mail?");
q.add(new q.Answer("ja", "Ja, bitte", "sendBestaetigungsMail"));
q.add(new q.Answer("nein", "Nein, danke", null));
view.add(q);
// Eigener Hook "sendBestaetigungsMail"
mail.send({ to: ctx.user.email, subject: "Bestellung", body: "Danke!" });
Solche Hooks legst du im Formular-Editor im Reiter Skripte über + Hook hinzufügen mit freiem Namen an.
ctx.requestClose() als Inline-Callback¶
Der häufigste Inline-Callback ist „Form schließen":
var q = new view.Question("Wirklich verwerfen und schließen?", { modal: true });
var yes = q.YES; yes.callback = function() { ctx.requestClose(); };
var no = q.NO;
q.add(yes); q.add(no);
view.add(q);
Hier funktioniert der Inline-Callback-Modus elegant: requestClose
setzt einen Flag, den der Server in dieselbe Antwort einbaut. Das
Frontend liest den Flag und schließt das Formular.
Trotzdem: nur EINMAL ausgeführt
Inline-Callbacks laufen direkt beim Aufbau des Dialogs —
nicht beim Klick. In dem requestClose-Beispiel oben schließt
das Formular also immer, sobald der Skript-Run vorbei ist —
egal ob der User „Ja" oder „Nein" klickt. Genau für diesen
Anwendungsfall ist das ok; für Klick-spezifische Logik nimm
Hook-Names statt Inline-Funktionen.
Modale vs. nicht-modale Dialoge¶
| Eigenschaft | modal: true |
modal: false (Default) |
|---|---|---|
| Backdrop | grauer Vorhang | nein |
| Position | mittig im Viewport | Banner oben am Form |
| Andere Aktionen | blockiert | parallel möglich |
| Mehrere | reihen sich auf | reihen sich auf |
| Geschlossen wird | per Button / Backdrop | per X (wenn closable) |
Banner-Mode ist nützlich für Hinweise, die parallel zum Formular-Editieren sichtbar bleiben sollen. Modal ist für „Antwort zwingend erforderlich".
Vollständiges Beispiel: Lösch-Workflow¶
// Hook "askDelete" (am Knopf "Löschen")
var q = new view.Question(
"Datensatz #" + ctx.instanceId + " wirklich löschen?",
{ caption: "Löschen", modal: true, color: "red" }
);
var yes = q.YES;
yes.callback = "doDelete"; // String → triggert eigenen Hook
var no = q.CANCEL; // null-Callback → einfach dismissen
q.add(yes);
q.add(no);
q.defaultAnswer = "cancel";
view.add(q);
// Hook "doDelete"
forms.delete(ctx.formId, ctx.instanceId); // räumt auch Anlagen und Detail-Zeilen ab
view.add(new view.Message("Gelöscht.", "Erfolg", { okButton: true }));
ctx.requestClose();
Was hier passiert:
- User klickt „Löschen" →
askDelete-Hook läuft, baut die Frage, schickt sie ans Frontend. - Frontend rendert modal mit „Ja"/„Abbrechen".
- Klickt der Anwender „Ja", läuft der Hook
doDelete— ein neuer Skript-Lauf mit derselbenctx.instanceId. doDeletelöscht aus der DB, zeigt die Erfolgsmeldung,requestClose()schließt das Form.
Stolperfallen¶
- Inline-Funktion erwartet Klick-Verhalten → falsch. Inline-Funktionen laufen sofort. Für eine Reaktion auf den Klick den Namen eines Hooks angeben.
q.add(q.YES)ohne Callback → das ist erlaubt und schließt beim Klick einfach den Dialog. Wenn du eine Reaktion willst, vorherq.YES.callback = "..."oderq.YES.callback = function() {...}.view.addmit etwas anderem alsMessage/Question→ Fehler.view.add(null)wird still ignoriert.newnicht vergessen —view.Message("…")ohnenewschlägt fehl.- Mehrere Dialoge aus einem Hook → erlaubt; das Frontend rendert alle in einem Stack. Aber: alle Inline-Funktionen feuern unmittelbar.