Zum Inhalt

Empfängerauswahl (Rezept)

Ein häufiges Muster: Ein Picker öffnet eine Auswahl mit Vorname, Nachname, E-Mail und Benutzerkennung. Die Einzelwerte landen in versteckten Feldern, im sichtbaren Feld „Empfänger" steht die Zusammenfassung „Nachname, Vorname (Kennung)". Ein Absenden-Knopf speichert den Datensatz, stempelt Absender und Zeitpunkt und verschickt im Namen des angemeldeten Benutzers eine Mail mit einem Link auf genau diesen Datensatz — danach verschwindet der Knopf, und der Link erscheint.

Das Muster gibt es zweifach:

  • als Baukasten-Baustein „Empfängerauswahl" (Ordner Feldgruppen) — legt die ganze Feldgruppe samt Skripten auf einmal an;
  • als Beispielformular „Empfängerauswahl (Demo)" (empfaenger-auswahl, Katalog Demo), installierbar unter System-Administration → Formular-Bausteine → Beispiele.

Diese Seite erklärt die Bausteine zum Verstehen und Nachbauen.

Baukasten-Baustein: alles kommt beim Ablegen mit

Beim Ablegen bekommen alle Feldnamen ein Präfix (empfaenger → empf_empfaenger). Der Baukasten schreibt dabei auch alle Verweise um: Zielfelder in kc:picker.set, Feldnamen in kc:visibleIf/kc:requiredIf, Makros wie ${value:empfaenger} und die Feldnamen in den mitgelieferten Skripten (onBeforeSave, onSubmit). Außerdem setzt er kc:reflectServerValues am Formular.

Gibt es am Formular schon ein gleichnamiges Skript, wird der Block des Bausteins mit einer Markierung angehängt (nicht überschrieben), und ein Hinweis nennt das zu prüfende Skript. Nach dem Ablegen nur noch Speichern — fertig.

Die Bausteine

1. Der Picker (Feld „Empfänger")

Der Picker sitzt auf dem sichtbaren Feld empfaenger. Quelle ist die KCForms-Benutzertabelle USERS im table-Modus — also komplett im Reiter Auswahl zusammenklickbar. Die Zusammenfassung entsteht über eine Textvorlage, das Auswahldatum über das Sondertoken @today:

"empfaenger": {
  "type": "string", "title": "Empfänger", "kc:readonly": true,
  "kc:maxLength": 160, "kc:placeholder": "Über … auswählen",
  "kc:lookupActiveIf": "kc.isEmpty(abgesendetAm)",
  "kc:picker": {
    "title": "Empfänger auswählen",
    "table": "USERS",
    "where": "ACC_STATUS = 1",
    "orderBy": "LAST_NAME, FIRST_NAME",
    "search":  ["FIRST_NAME", "LAST_NAME", "EMAIL", "LOGIN_NAME"],
    "columns": [
      { "column": "FIRST_NAME", "title": "Vorname" },
      { "column": "LAST_NAME",  "title": "Nachname" },
      { "column": "EMAIL",      "title": "E-Mail" },
      { "column": "LOGIN_NAME", "title": "Benutzerkennung" }
    ],
    "pageSize": 10,
    "set": {
      "empfaenger":       "{LAST_NAME}, {FIRST_NAME} ({LOGIN_NAME})",
      "empfVorname":      "FIRST_NAME",
      "empfNachname":     "LAST_NAME",
      "empfEmail":        "EMAIL",
      "empfKennung":      "LOGIN_NAME",
      "empfAuswahlDatum": "@today"
    }
  }
}
  • table + where: Basis-Tabelle plus fester Filter; die Suche verknüpft der Server per AND.
  • set: Zielfeld ← Quelle — eine Spalte, eine Textvorlage mit {SPALTE}-Platzhaltern oder ein Sondertoken (@today, @now).
  • Das Feld ist kc:readonly — gewählt wird nur über den Picker.
  • kc:lookupActiveIf: "kc.isEmpty(abgesendetAm)" sperrt die Auswahl nach dem Versand: Sobald abgesendetAm gefüllt ist, verschwindet der …-Knopf.

Andere Quelle statt USERS (siehe Picker):

  • LDAP/AD: "ldapConnector": "<name>", optional ldapBase/ldapFilter; columns/set auf LDAP-Attribute (givenName, sn, mail, uid).
  • Externe Datenbank: zusätzlich "dataSourceId": <id> zu table/sql.

2. Die versteckten Felder

kc:visible: false blendet ein Feld aus, behält aber den Wert (kein kc:clearIfInvisible setzen):

"empfVorname":      { "type": "string", "title": "Vorname (Empfänger)",         "kc:maxLength": 80,  "kc:visible": false },
"empfNachname":     { "type": "string", "title": "Nachname (Empfänger)",        "kc:maxLength": 80,  "kc:visible": false },
"empfEmail":        { "type": "string", "title": "E-Mail (Empfänger)",          "kc:maxLength": 120, "kc:visible": false },
"empfKennung":      { "type": "string", "title": "Benutzerkennung (Empfänger)", "kc:maxLength": 80,  "kc:visible": false },
"empfAuswahlDatum": { "type": "string", "format": "date", "title": "Datum der Empfängerauswahl", "kc:visible": false }

format: "date" erzeugt eine DATE-Spalte. kc:maxLength legt die Spaltenbreite fest (ohne Angabe VARCHAR(255)).

Versteckte Felder im Formular-Editor sehen

In der Vorschau des Formular-Editors blendet der Schalter Ausgeblendete anzeigen solche Felder zum Bearbeiten ein.

3. Versand-Felder und Absenden-Knopf

„Abgesendet von/am" sind sichtbar und schreibgeschützt — sie werden gestempelt, nicht getippt. Der Datensatz-Link erscheint erst, wenn er gefüllt ist. Der Knopf löst die normale Speicherung aus (scriptHook: "saveForm") und ist nur sichtbar, solange abgesendetAm leer ist:

"abgesendetVon":   { "type": "string", "title": "Abgesendet von", "kc:maxLength": 120, "kc:readonly": true },
"abgesendetAm":    { "type": "string", "title": "Abgesendet am",  "kc:maxLength": 20,  "kc:readonly": true },
"absenderKennung": { "type": "string", "title": "Benutzerkennung (Absender)", "kc:maxLength": 80, "kc:visible": false },
"datensatzLink": {
  "type": "string", "title": "Link zum Datensatz", "kc:maxLength": 300,
  "kc:readonly": true, "kc:colspan": "full",
  "kc:visibleIf": "!kc.isEmpty(datensatzLink)"
},
"btn_absenden": {
  "type": "string", "title": "", "kc:colspan": "full",
  "kc:button": { "label": "Absenden", "variant": "primary", "scriptHook": "saveForm" },
  "kc:tooltip": { "text": "Absenden an ${value:empfaenger}" },
  "kc:visibleIf": "kc.isEmpty(abgesendetAm)"
}

Am Schema-Root steht "kc:reflectServerValues": true: Der Server spiegelt die in den Skripten gesetzten Werte (Stempel und Link) zurück in die Maske. Nur so verschwindet der Knopf sofort nach dem Versand und der Link wird sichtbar, ohne den Datensatz neu zu laden.

Tooltip nennt den Empfänger

kc:tooltip.text darf Makros enthalten: ${value:empfaenger} zeigt zur Laufzeit den aktuellen Feldwert — der Tooltip lautet dann etwa „Absenden an Bauer, Tobias (tbauer)".

Zweispaltiges Layout

Der Abschnitt trägt kc:sectionLayout: "horizontal-2". Ohne kc:colspan belegt ein Feld eine Spalte: Empfänger steht links mit einem kc:spacer daneben, darunter Abgesendet von / am nebeneinander. Der Knopf spannt mit kc:colspan: "full" über beide Spalten.

4. Die Skripte

„Absenden" ist eine normale Speicherung. Die Logik verteilt sich auf zwei Skripte der Speicher-Pipeline, weil der Link erst nach dem Speichern gebaut werden kann (er braucht die Datensatz-ID):

  • onBeforeSave läuft vor dem Speichern. Ist ein Empfänger gewählt und noch nicht abgesendet, stempelt es Absender und Zeitpunkt — diese Werte werden mitgespeichert. Das Hilfsfeld _sendNow signalisiert onSubmit den Versand (Felder mit _ stehen nicht im Schema und werden weder gespeichert noch zurückgespiegelt).
// onBeforeSave
if (ctx.form.empfEmail && !ctx.form.abgesendetAm) {
  ctx.form.abgesendetVon   = macros.resolve('${user:lastName}, ${user:firstName} (${user:name})');
  ctx.form.abgesendetAm    = macros.resolve('${datetime(dd.MM.yyyy HH:mm)|now}');
  ctx.form.absenderKennung = macros.resolve('${user:name}');
  ctx.form._sendNow = true;
}
  • onSubmit läuft nach dem Speichern (ctx.instanceId ist gesetzt). Es baut den Link auf diesen Datensatz (mail.newAdhocInvocation), trägt ihn mit ctx.persist('datensatzLink') nach und mailt ihn im Namen des angemeldeten Benutzers:
// onSubmit
if (ctx.form._sendNow) {
  var inv = mail.newAdhocInvocation('any');   // { id, url } — Link auf diesen Datensatz
  ctx.form.datensatzLink = inv.url;
  ctx.persist('datensatzLink');               // Link in die gespeicherte Zeile nachtragen

  var msg = mail.newMessage();
  if (ctx.user && ctx.user.email) { msg.from = ctx.user.email; }
  msg.to      = ctx.form.empfEmail;
  msg.subject = 'Zustellung aus KCForms';
  msg.text    = 'Hallo ' + (ctx.form.empfVorname || '') + ',\n\n'
              + 'Empfänger: ' + ctx.form.empfaenger + '\n'
              + 'Link zum Datensatz: ${url}\n';
  mail.send(msg, inv);   // ersetzt ${url} durch inv.url
}

Absender und Freigabeliste

msg.from = ctx.user.email verschickt im Namen des Anwenders. Der Mailserver muss diese Absenderadresse zulassen (viele Anbieter erlauben nur Adressen des angemeldeten Postfachs) — sonst kommt ein Zustellfehler zurück. Die Empfänger-Domain muss ggf. auf der Empfänger-Freigabeliste stehen.

Nachbauen — Schritt für Schritt

  1. Felder anlegen: empfaenger (mit dem Picker oben), die fünf versteckten empf*-Felder, abgesendetVon, abgesendetAm, absenderKennung, datensatzLink, btn_absenden (scriptHook: "saveForm").
  2. Am Schema-Root "kc:reflectServerValues": true setzen.
  3. Im Reiter Skripte onBeforeSave (Stempel) und onSubmit (Link und Mail) anlegen.
  4. Fertig — der Picker füllt Zusammenfassung und versteckte Felder, Absenden speichert, stempelt, mailt den Link und verschwindet.

Schneller: den Baukasten-Baustein ziehen oder das Beispielformular empfaenger-auswahl duplizieren.