View Categories

08 HTML-Formulare

HTML-Formulare der MCDMS WebAkte sind normale HTML-Dokumente.

Sie können verwendet werden für:

  • Eingabeformulare
  • Patientenübersichten
  • Master-/Detailformulare
  • Listen
  • Dashboards
  • Scriptfunktionen
  • Informationsseiten
  • klinikspezifische Oberflächen

Verwendet werden können:

HTML5
CSS
JavaScript

MCDMS-spezifische Erweiterungen werden nur dort benötigt, wo Daten aus MCDMS oder der WebAkte eingebunden werden.

1. Grundgerüst

Eine HTML-Datei sollte mindestens folgendes Grundgerüst besitzen:

<!doctype html>
<html lang="de">
<head>
    <meta charset="utf-8">

    <meta name="viewport"
          content="width=device-width, initial-scale=1.0">

    <title>Mein Formular</title>

    <style>
        /* eigenes CSS */
    </style>
</head>

<body>

<form class="mein-formular">
    <!-- Formularinhalt -->
</form>

<script>
    /* eigenes JavaScript */
</script>

</body>
</html>

Wichtig sind insbesondere:

UTF-8
viewport
eigener Formular-Root

Für jedes Formular sollte eine eigene Root-Klasse verwendet werden.

Beispiel:

<form class="mein-formular">

Dadurch kann das CSS des Formulars sauber von der WebAkte-Oberfläche getrennt werden.

2. Templatevariablen

MCDMS-, Server- und Formulardaten können über folgende Syntax eingebunden werden:

[#FELDNAME#]

Beispiel:

<div>
    Patient:
    <strong>[#GESAMTNAME#]</strong>
</div>

oder:

<div>
    Geburtsdatum:
    [#GEBDATUM#]
</div>

3. Anzeigeelemente

Soll ein Wert lediglich angezeigt werden, benötigt das Element kein name.

Beispiel:

<div data-field="GESAMTNAME">
    [#GESAMTNAME#]
</div>

Ein solches Feld wird nicht als beschreibbares Masterfeld gespeichert.

Das ist insbesondere sinnvoll für:

  • Patientendaten
  • Diagnosen
  • berechnete Werte
  • Scriptwerte
  • Statusinformationen

4. Editierbare Masterfelder

Ein editierbares Masterfeld benötigt mindestens:

name
data-field

Beide Werte müssen identisch sein.

Beispiel:

<input type="text"
       name="BEMERKUNG"
       data-field="BEMERKUNG"
       value="[#BEMERKUNG#]">

Richtig:

name="BEMERKUNG"
data-field="BEMERKUNG"

Falsch:

name="Bemerkung"
data-field="BEMERKUNG"

Für ein Formular mit:

Edit=TRUE

muss jedes echte editierbare Masterfeld einer real vorhandenen und beschreibbaren Datenbankspalte entsprechen.

Andernfalls wird das Speichern kontrolliert abgebrochen.

5. Textfelder

Beispiel:

<input type="text"
       name="ORT"
       data-field="ORT"
       value="[#ORT#]">

Zusätzlich können normale HTML-Attribute verwendet werden:

<input type="text"
       name="ORT"
       data-field="ORT"
       maxlength="100"
       required>

6. Mehrzeilige Textfelder

Für längere Texte:

<textarea name="FRAGESTELLUNG"
          data-field="FRAGESTELLUNG">[#FRAGESTELLUNG#]</textarea>

Geeignet beispielsweise für:

  • Bemerkungen
  • Freitext
  • Anamnese
  • Fragestellungen
  • klinische Angaben

7. Readonly-Felder

Soll ein Datenbankwert angezeigt, aber nicht geändert werden:

<input type="text"
       name="USERID"
       data-field="USERID"
       value="[#USERID#]"
       readonly>

Soll der Wert ausschließlich dargestellt werden, ist besser:

<div data-field="USERID">
    [#USERID#]
</div>

Dann wird er nicht als editierbares Formularfeld behandelt.

8. Hidden-Felder

Auch versteckte Felder können normale Masterfelder sein:

<input type="hidden"
       name="ErstelltVon"
       data-field="ErstelltVon"
       value="[#ErstelltVon#]">

Beispiel:

<input type="hidden"
       name="ErstelltAm"
       data-field="ErstelltAm"
       value="[#ErstelltAm#]">

Wichtig:

hidden bedeutet nur unsichtbar im Browser.

Der Wert bleibt Browserinhalt und wird serverseitig vollständig validiert.

9. Checkboxen

Beispiel:

<input type="checkbox"
       name="BTM"
       data-field="BTM">

Bei SQL-bit-Feldern ist keine eigene Sonderlogik notwendig.

Die WebAkte verarbeitet den Checkboxzustand beim Speichern.

10. Radio-Buttons

Mehrere Radio-Buttons gehören zu demselben Formularfeld, wenn sie denselben:

name
data-field

verwenden.

Beispiel:

<label>
    <input type="radio"
           name="GESCHLECHT"
           data-field="GESCHLECHT"
           value="M">
    männlich
</label>

<label>
    <input type="radio"
           name="GESCHLECHT"
           data-field="GESCHLECHT"
           value="W">
    weiblich
</label>

Gespeichert wird der Wert des ausgewählten Controls.

11. Auswahlfelder

Normale HTML-select-Elemente können verwendet werden:

<select name="STATUS"
        data-field="STATUS">

    <option value="">Bitte wählen</option>
    <option value="A">Aktiv</option>
    <option value="B">Beendet</option>

</select>

12. Datumsfelder

Die WebAkte unterstützt native HTML5-Feldtypen.

Datum:

<input type="date"
       name="DATUM"
       data-field="DATUM">

13. Zeitfelder

<input type="time"
       name="UHRZEIT"
       data-field="UHRZEIT">

14. Datum und Uhrzeit

<input type="datetime-local"
       name="ZEITPUNKT"
       data-field="ZEITPUNKT">

15. Zahlenfelder

<input type="number"
       name="MENGE"
       data-field="MENGE">

Normale HTML-Attribute können verwendet werden:

min
max
step

Beispiel:

<input type="number"
       name="MENGE"
       data-field="MENGE"
       min="0"
       step="1">

Zusätzliche MCDMS-spezifische Typattribute sind nicht erforderlich.

16. Speichern

Die Speichern-Funktion wird zentral von der WebAkte bereitgestellt.

Bei:

Edit=TRUE

wird automatisch eine Speichern-Schaltfläche angezeigt.

Bei:

DoubleSaveButton=TRUE

stehen bei langen Formularen oben und unten Speichern-Schaltflächen zur Verfügung.

Ein eigener Save-Button im Formular-HTML ist normalerweise nicht erforderlich.

17. Normale Buttons

Buttons, die nicht speichern sollen, müssen ausdrücklich:

type="button"

verwenden.

Beispiel:

<button type="button">
    Suchen
</button>

Nicht empfohlen:

<button>
    Suchen
</button>

weil ein solcher Button innerhalb eines Formulars als Submit-Button interpretiert werden kann.

18. Actions

Für serverseitige MCDMS-Actions:

<button type="button"
        data-mcdms-action="DRUCKEN">
    Drucken
</button>

Die passende serverseitige Konfiguration erfolgt in FORMULARE.INI.

19. CSS auf das Formular begrenzen

Formular-HTML wird innerhalb der WebAkte dargestellt.

Deshalb sollten globale CSS-Regeln vermieden werden.

Nicht empfohlen:

* {
    box-sizing: border-box;
}

button {
    background: blue;
}

input {
    color: black;
}

Besser:

.mein-formular,
.mein-formular * {
    box-sizing: border-box;
}

.mein-formular button {
    background: #2b6cb0;
}

.mein-formular input {
    color: #1a202c;
}

20. Breite des Formulars

Das Formular entscheidet selbst über seine Darstellung.

Volle Breite:

.mein-formular {
    width: 100%;
}

Begrenzte Breite:

.mein-formular {
    max-width: 1200px;
    margin: 0 auto;
}

21. Hintergrund und Formularbereich

Der body sollte möglichst neutral bleiben:

body {
    margin: 0;
    padding: 0;
    background: transparent;
}

Abstände und Hintergründe besser im eigenen Formularbereich definieren:

.mein-formular {
    padding: 20px;
}

22. Formular unabhängig vom WebAkte-Theme gestalten

Formulare sollten nicht davon abhängig sein, wie Browser oder WebAkte-Theme native Controls darstellen.

Beispiel:

.mein-formular input,
.mein-formular textarea,
.mein-formular select {
    width: 100%;
    box-sizing: border-box;

    background: #ffffff;
    color: #1a202c;

    border: 1px solid #cbd5e1;
    border-radius: 8px;

    padding: 8px 10px;
}

Dadurch bleibt das Formular auch bei unterschiedlichen Shell-Themes lesbar.

23. Master-/Detailformulare

Für wiederholbare Datensätze sollten keine festen Feldnamen wie:

DATUM1
DATUM2
DATUM3
DATUM4

verwendet werden.

Dafür stehen Detailzeilen zur Verfügung.

24. Detailcontainer

Ein Detailbereich wird mit:

data-mcdms-detail-list

gekennzeichnet.

Beispiel:

<table>
    <tbody data-mcdms-detail-list>
    </tbody>
</table>

25. Detailtemplate

Es gibt genau ein gemeinsames Template:

<template data-mcdms-detail-row>

    <tr>
        <td>
            <input type="date"
                   data-detail-field="DATUM">
        </td>

        <td>
            <input type="text"
                   data-detail-field="BEMERKUNG">
        </td>
    </tr>

</template>

data-detail-field ordnet das Control einer Spalte der Detailtabelle zu.

26. Mehrere Detailcontainer

Ein Master-/Detailformular kann 1..n statische Detailcontainer besitzen.

Beispiel:

<table>
    <tbody data-mcdms-detail-list
           data-med-area-list="REGEL">
    </tbody>
</table>

<table>
    <tbody data-mcdms-detail-list
           data-med-area-list="BESONDERE_ZEITEN">
    </tbody>
</table>

<table>
    <tbody data-mcdms-detail-list
           data-med-area-list="SELBST">
    </tbody>
</table>

Es bleibt dennoch:

ein Detailmodell
ein gemeinsames Template
eine gemeinsame Detailfeld-Allowlist

Die WebAkte sammelt beim Speichern alle statischen [data-mcdms-detail-list]-Container in Dokumentreihenfolge. Das ist inzwischen generisch im Frontend unterstützt. app

27. Fachliche Aufteilung von Details

Die WebAkte interpretiert eigene Attribute wie:

data-med-area-list

nicht fachlich.

Die Zuordnung kann beispielsweise über ein normales Detailfeld erfolgen:

<input type="hidden"
       data-detail-field="BEREICH">

Mögliche Werte:

REGEL
BESONDERE_ZEITEN
SELBST

Das Formular-JavaScript kann die geladenen Zeilen anhand dieses Feldes auf die sichtbaren Tabellen verteilen.

28. Neue Detailzeile erzeugen

Beispiel:

function addDetailRow(list) {
    const template =
        document.querySelector(
            'template[data-mcdms-detail-row]'
        );

    const row =
        template.content
            .firstElementChild
            .cloneNode(true);

    list.appendChild(row);

    return row;
}

Bei mehreren Detailcontainern sollte der Zielcontainer explizit übergeben werden.

29. Detailzeile löschen

Eine Detailzeile wird formularseitig aus dem DOM entfernt.

Beispiel:

function deleteRow(button) {
    const row = button.closest('tr');

    if (!row) {
        return;
    }

    row.remove();
}

Beim Speichern entspricht der aktuell sichtbare Detailbestand dem gewünschten Detailbestand.

30. Detailzeile verschieben

Beispiel:

function moveRow(button, direction) {

    const row = button.closest('tr');

    if (!row) {
        return;
    }

    if (direction === 'up') {

        const previous = row.previousElementSibling;

        if (previous) {
            row.parentNode.insertBefore(row, previous);
        }

    } else if (direction === 'down') {

        const next = row.nextElementSibling;

        if (next) {
            row.parentNode.insertBefore(
                next,
                row
            );
        }
    }
}

Bei mehreren fachlichen Bereichen sollte eine Zeile normalerweise nur innerhalb ihres eigenen Bereichs verschoben werden.

31. Detailzeile duplizieren

Beispiel:

function duplicateRow(button) {

    const source = button.closest('tr');

    if (!source) {
        return;
    }

    const copy = source.cloneNode(true);

    const sourceControls =
        source.querySelectorAll(
            'input, select, textarea'
        );

    const copyControls =
        copy.querySelectorAll(
            'input, select, textarea'
        );

    sourceControls.forEach(function(control, index) {

        const clone = copyControls[index];

        if (
            control.type === 'checkbox' ||
            control.type === 'radio'
        ) {
            clone.checked = control.checked;
        } else {
            clone.value = control.value;
        }
    });

    source.parentNode.insertBefore(
        copy,
        source.nextSibling
    );
}

32. JavaScript-Werte ändern

Wird ein Formularfeld per JavaScript verändert, sollten anschließend normale Browserereignisse ausgelöst werden.

Beispiel:

field.value = 'Test';

field.dispatchEvent(
    new Event('input', {
        bubbles: true
    })
);

field.dispatchEvent(
    new Event('change', {
        bubbles: true
    })
);

Dadurch erkennen auch WebAkte-Funktionen die Änderung korrekt.

33. Partial Refresh beachten

Nach dem Speichern wird der Formularbereich aktualisiert, ohne dass die gesamte WebAkte neu geladen werden muss.

Dabei werden vorhandene DOM-Strukturen soweit möglich abgeglichen.

Wichtig:

Identische Formular-<script>-Elemente werden dabei nicht automatisch erneut ausgeführt. Formular-JavaScript muss daher DOM-Austausch berücksichtigen. PROJECT-HANDOVER

Empfohlen sind:

Event Delegation
idempotente Initialisierung
MutationObserver nur dort, wo nötig

34. Event Delegation

Statt jede dynamische Zeile einzeln zu binden:

document.addEventListener('click', function(event) {

    const button =
        event.target.closest(
            '[data-delete-row]'
        );

    if (!button) {
        return;
    }

    const row = button.closest('tr');

    if (row) {
        row.remove();
    }
});

Dadurch funktioniert die Logik auch für später erzeugte oder neu gerenderte Zeilen.

35. JavaScript nicht mehrfach initialisieren

Wenn eine Initialisierung notwendig ist, sollte sie idempotent sein.

Beispiel:

function initializeRow(row) {

    if (!row) {
        return;
    }

    if (row.dataset.initialized === '1') {
        return;
    }

    row.dataset.initialized = '1';

    // Initialisierung
}

Dabei muss trotzdem berücksichtigt werden, dass sich Werte durch einen Partial Refresh ändern können.

Reine visuelle Zustände sollten deshalb aus den aktuellen Controlwerten ableitbar bleiben.

36. Mobile Darstellung

Formulare sollten responsive aufgebaut werden.

Mindestens:

<meta name="viewport"
      content="width=device-width, initial-scale=1.0">

Beispiel:

@media (max-width: 768px) {

    .mein-formular .grid {
        grid-template-columns: 1fr;
    }
}

Controls sollten auf kleinen Displays nicht nur über feste Pixelpositionen erreichbar sein.

37. Lokale Ressourcen

Die WebAkte stellt lokale Bereiche bereit:

/CSS/
/JS/
/IMAGES/

Beispiel:

<script src="/JS/mein-script.js"></script>

oder:

<img src="/IMAGES/logo.png"
     alt="Kliniklogo">

Externe Abhängigkeiten sollten vermieden werden.

Insbesondere sollte ein Klinikformular nicht von externen CDNs abhängig sein.

38. MCDMS-Werte in JavaScript

Templatevariablen sollten nicht direkt ungeprüft in JavaScript-Code eingesetzt werden.

Nicht empfohlen:

const wert = '[#MEINEVARIABLE#]';

Sicherer ist beispielsweise:

<div id="mcdms-data"
     hidden>[#MEINEVARIABLE#]</div>

und anschließend:

const element =
    document.getElementById('mcdms-data');

const value =
    element
        ? element.textContent
        : '';

Dadurch wird ein MCDMS-Wert nicht versehentlich als JavaScript-Code interpretiert.

39. Zeilenumbrüche anzeigen

Normales HTML stellt CR/LF nicht automatisch als sichtbaren Zeilenumbruch dar.

Für Textwerte mit Zeilenumbrüchen:

<div style="white-space: pre-line">
    [#DIAGNOSEN#]
</div>

oder besser per CSS:

.mein-formular .mehrzeiliger-text {
    white-space: pre-line;
}

Beispiel:

<div class="mehrzeiliger-text">
    [#DIAGNOSEN#]
</div>

40. Dynamisches HTML

Soll ein MCDMS-/Scriptwert bewusst als HTML ausgegeben werden:

<div data-mcdms-html="MEINEVARIABLE"></div>

Dieser Inhalt wird serverseitig kontrolliert und bereinigt.

Für normale Textausgabe sollte weiterhin:

[#VARIABLE#]

verwendet werden.

41. RecordView=LIST

Für RecordView=LIST gelten eigene HTML-Attribute.

Container:

<div data-mcdms-record-list>
</div>

Gemeinsames Template:

<template data-mcdms-record-row>

    <div>
        <input data-record-field="ICD">
        <input data-record-field="TEXT">
    </div>

</template>

Felder:

data-record-field

Die WebAkte sammelt die Recordlisten und deren Felder beim LIST-Speichern separat vom normalen Master-/Detailmodell. app

42. LIST-Datensatz hinzufügen

Ein neu erzeugter LIST-Datensatz wird aus dem gemeinsamen Recordtemplate erzeugt.

Die WebAkte unterscheidet dabei:

  • vorhandene Records
  • neue Records
  • Duplikate
  • gelöschte Records

Die technischen IDs werden serverseitig verarbeitet.

43. LIST-Datensatz löschen

Für die generische LIST-Bedienung steht das Attribut:

data-mcdms-record-delete

zur Verfügung.

Beispiel:

<button type="button"
        data-mcdms-record-delete>
    Löschen
</button>

44. LIST-Datensatz duplizieren

<button type="button"
        data-mcdms-record-duplicate>
    Duplizieren
</button>

45. LIST-Datensatz verschieben

<button type="button"
        data-mcdms-record-move-up>
    ↑
</button>

<button type="button"
        data-mcdms-record-move-down>
    ↓
</button>

Die WebAkte berücksichtigt die aktuelle Reihenfolge beim Speichern.

46. Persistente LIST-Sortierung

Ein Feld kann zusätzlich mit:

data-mcdms-record-order

gekennzeichnet werden.

Beispiel:

<input type="hidden"
       data-record-field="ICDRANG"
       data-mcdms-record-order>

Beim Speichern wird die sichtbare Reihenfolge normalisiert.

47. HTML-Validierung

Normales valides HTML sollte eingehalten werden.

Beispielsweise dürfen Controls in einer Tabelle nicht beliebig direkt unter einem <tr> liegen.

Richtig:

<tr>
    <td>
        <input type="hidden"
               data-detail-field="BEREICH">
    </td>
</tr>

Nicht:

<tr>
    <input type="hidden"
           data-detail-field="BEREICH">
</tr>

Browser können ungültiges Tabellenmarkup automatisch umstrukturieren und dadurch JavaScript-/Detaillogik unerwartet verändern.

48. Häufige Fehler

Unterschiedliche Feldnamen

Falsch:

<input type="text"
       name="Feld1"
       data-field="FELD1">

Richtig:

<input type="text"
       name="FELD1"
       data-field="FELD1">

data-field fehlt

Falsch:

<input type="text"
       name="BEMERKUNG">

Richtig:

<input type="text"
       name="BEMERKUNG"
       data-field="BEMERKUNG">

Button ohne type

Falsch:

<button>
    Löschen
</button>

Richtig:

<button type="button">
    Löschen
</button>

Globale CSS-Regel

Nicht empfohlen:

button {
    background: blue;
}

Besser:

.mein-formular button {
    background: blue;
}

PatientVar mit SQL-Feld verwechselt

Eine PatientVar allein erzeugt keine SQL-Speicherung.

Für ein reales Masterfeld wird weiterhin benötigt:

name="FELD"
data-field="FELD"

Detailfeld mit name versehen

Detailfelder benötigen grundsätzlich:

data-detail-field

Sie gehören nicht zum normalen Master-name/data-field-Vertrag.

Aktuelles Datum bei jedem Speichern setzen

Soll ein Datenbankfeld wie DATE nicht nur bei einem neuen Datensatz vorbelegt werden, sondern bei jedem erneuten Speichern auf das aktuelle Datum gesetzt werden, reicht ein normaler Platzhalter im Hidden-Feld nicht aus.

Beispiel:

<input type="hidden"
       name="DATE"
       data-field="DATE"
       value="[#DATE#]">

Bei bestehenden Datensätzen ist der bereits gespeicherte Datenbankwert maßgeblich. Ein gleichnamiger Wert aus ScriptLoadHTML überschreibt diesen vorhandenen SQL-Wert bewusst nicht. ScriptLoadHTML kann bei einem neuen Datensatz ein noch unbelegtes Feld initialisieren; bei vorhandenen Datensätzen bleibt die Datenbank die maßgebliche Quelle. PROJECT-HANDOVER

Soll DATE deshalb bei jedem Speichern auf das aktuelle Tagesdatum gesetzt werden, kann das echte Formularfeld vor dem Speichern per JavaScript aktualisiert werden:

<input type="hidden"
       name="DATE"
       data-field="DATE"
       value="[#DATE#]">

<script>
(function () {

    const field =
        document.querySelector(
            'input[name="DATE"][data-field="DATE"]'
        );

    if (!field) {
        return;
    }

    const today = new Date();

    const year = today.getFullYear();
    const month =
        String(today.getMonth() + 1).padStart(2, '0');
    const day =
        String(today.getDate()).padStart(2, '0');

    field.value =
        year + '-' + month + '-' + day;

    field.dispatchEvent(
        new Event('input', { bubbles: true })
    );

    field.dispatchEvent(
        new Event('change', { bubbles: true })
    );

})();
</script>

Dadurch wird beispielsweise aus:

gespeichert:
DATE = 2026-10-12

beim erneuten Öffnen und Speichern am 14.10.2026:

DATE = 2026-10-14

Wichtig ist, dass DATE weiterhin ein echtes Masterfeld ist:

name="DATE"
data-field="DATE"

und eine reale beschreibbare Datenbankspalte DATE vorhanden ist.

Unterschied zu einem Erstellungsdatum

ErstelltAm

soll normalerweise das ursprüngliche Erstellungsdatum behalten.

DATE

kann dagegen – wenn fachlich gewünscht – als Datum der letzten Bearbeitung bzw. Speicherung verwendet werden.

Die WebAkte setzt solche Auditfelder nicht automatisch aufgrund ihres Namens. Wenn ein Feld bei jeder Speicherung aktualisiert werden soll, muss dieses Verhalten ausdrücklich im Formular bzw. in der Fachlogik vorgesehen werden.

49. Checkliste

Vor Einsatz eines Formulars sollte geprüft werden:

✓ <!doctype html> vorhanden

✓ UTF-8 verwendet

✓ viewport vorhanden

✓ eigener Formular-Root vorhanden

✓ CSS vollständig auf Formular begrenzt

✓ keine globalen CSS-Regeln

✓ jedes editierbare Masterfeld besitzt name

✓ jedes editierbare Masterfeld besitzt data-field

✓ name und data-field stimmen überein

✓ SQL-/Access-Spalten existieren tatsächlich

✓ technische Felder werden nicht browserseitig geschrieben

✓ native HTML-Feldtypen verwendet

✓ normale Buttons verwenden type="button"

✓ zentrale Save-Funktion wird verwendet

✓ responsive Darstellung geprüft

✓ keine zwingenden externen Abhängigkeiten

✓ JavaScript berücksichtigt Partial Refresh

✓ dynamisch gesetzte Werte lösen input/change aus

✓ bei Detailformular mindestens ein data-mcdms-detail-list

✓ genau ein template[data-mcdms-detail-row]

✓ Detailfelder verwenden data-detail-field

✓ mehrere Detaillisten sind statisch im HTML definiert

✓ bei LIST data-mcdms-record-list vorhanden

✓ bei LIST template[data-mcdms-record-row] vorhanden

✓ bei LIST data-record-field korrekt verwendet

✓ Tabellenmarkup ist valides HTML

50. Minimalbeispiel

<!doctype html>
<html lang="de">

<head>

    <meta charset="utf-8">

    <meta name="viewport"
          content="width=device-width, initial-scale=1.0">

    <title>MCDMS Formular</title>

    <style>

        body {
            margin: 0;
            padding: 0;
            background: transparent;
        }

        .mcdms-beispiel,
        .mcdms-beispiel * {
            box-sizing: border-box;
        }

        .mcdms-beispiel {
            width: 100%;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;

            font-family:
                "Segoe UI",
                Arial,
                sans-serif;
        }

        .mcdms-beispiel .card {
            background: #ffffff;
            color: #1a202c;

            border: 1px solid #e2e8f0;
            border-radius: 12px;

            padding: 20px;
        }

        .mcdms-beispiel .row {
            margin-bottom: 12px;
        }

        .mcdms-beispiel input,
        .mcdms-beispiel textarea,
        .mcdms-beispiel select {
            width: 100%;
            box-sizing: border-box;

            padding: 8px 10px;

            background: #ffffff;
            color: #1a202c;

            border: 1px solid #cbd5e1;
            border-radius: 6px;
        }

    </style>

</head>

<body>

<form class="mcdms-beispiel">

    <div class="card">

        <h2>Beispiel</h2>

        <div class="row">
            Patient:
            <strong>
                [#GESAMTNAME#]
            </strong>
        </div>

        <div class="row">

            <label for="bemerkung">
                Bemerkung
            </label>

            <input type="text"
                   id="bemerkung"
                   name="BEMERKUNG"
                   data-field="BEMERKUNG"
                   value="[#BEMERKUNG#]">

        </div>

    </div>

</form>

</body>
</html>

Technische Leitlinien

HTML-Formulare müssen so aufgebaut sein, dass die WebAkte Datenfelder eindeutig erkennen, laden und speichern kann. Besonders für automatisch erzeugte Formulare oder Konverter sollten die folgenden Muster eingehalten werden.

Formular-Root und CSS

Jedes Formular sollte einen eigenen Root-Container besitzen:

<div class="mcdms-meinformular">
    ...
</div>

CSS sollte ausschließlich innerhalb dieses Bereichs wirken:

.mcdms-meinformular input {
    width: 100%;
}

Nicht verwenden:

input {
    width: 100%;
}

Globale CSS-Regeln könnten sonst die WebAkte-Shell beeinflussen.

Einfaches Textfeld

Ein beschreibbares Masterfeld benötigt immer:

  • name
  • data-field
  • beide Werte identisch
<input type="text"
       name="NACHNAME"
       data-field="NACHNAME"
       value="[#NACHNAME#]">

NACHNAME muss einer beschreibbaren Spalte der konfigurierten Mastertabelle entsprechen.

Mehrzeiliges Textfeld

<textarea name="BEMERKUNG"
          data-field="BEMERKUNG">[#BEMERKUNG#]</textarea>

Datumsfeld

Native HTML-Typen verwenden:

<input type="date"
       name="DATUM"
       data-field="DATUM"
       value="[#DATUM#]">

Keine eigene Datumskomponente ist erforderlich.

Uhrzeit

<input type="time"
       name="UHRZEIT"
       data-field="UHRZEIT"
       value="[#UHRZEIT#]">

Datum und Uhrzeit

<input type="datetime-local"
       name="ZEITPUNKT"
       data-field="ZEITPUNKT"
       value="[#ZEITPUNKT#]">

Zahlenfeld

<input type="number"
       name="GEWICHT"
       data-field="GEWICHT"
       step="0.1"
       value="[#GEWICHT#]">

Auswahlliste

<select name="STATUS"
        data-field="STATUS">
    <option value=""></option>
    <option value="A">Aktiv</option>
    <option value="P">Pausiert</option>
    <option value="B">Beendet</option>
</select>

Die WebAkte setzt beim Rendern die zum gespeicherten Wert passende Option.

Checkbox

<input type="checkbox"
       name="FREIGABE"
       data-field="FREIGABE">

Checkboxen werden wie normale Formularfelder behandelt.

Radiobuttons

Mehrere Radiobuttons gehören fachlich zu demselben Feld und verwenden daher denselben name– und data-field-Wert:

<label>
    <input type="radio"
           name="GESCHLECHT"
           data-field="GESCHLECHT"
           value="M">
    männlich
</label>

<label>
    <input type="radio"
           name="GESCHLECHT"
           data-field="GESCHLECHT"
           value="W">
    weiblich
</label>

<label>
    <input type="radio"
           name="GESCHLECHT"
           data-field="GESCHLECHT"
           value="D">
    divers
</label>

Verstecktes Feld

Auch Hidden-Felder können echte Masterfelder sein:

<input type="hidden"
       name="ERSTELLTVON"
       data-field="ERSTELLTVON"
       value="[#ERSTELLTVON#]">

Hidden-Felder sind normale Browserwerte und werden serverseitig genauso geprüft wie sichtbare Felder.

Nur anzeigen, nicht speichern

Soll ein Wert nur angezeigt werden, darf kein name gesetzt werden.

Beispiel:

<span data-field="GESAMTNAME">[#GESAMTNAME#]</span>

oder einfach:

<strong>[#GESAMTNAME#]</strong>

Ein Element mit data-field, aber ohne name, wird nicht als beschreibbares Masterfeld verwendet.

Readonly-Feld

<input type="text"
       name="FALLNUMMER"
       data-field="FALLNUMMER"
       value="[#FALLNUMMER#]"
       readonly>

readonly verhindert die normale Benutzereingabe im Browser. Das Feld bleibt technisch ein Masterfeld.

Normale Schaltflächen

Schaltflächen, die keine Formularspeicherung auslösen sollen, immer mit:

<button type="button">Auswahl öffnen</button>

Nicht einfach:

<button>Auswahl öffnen</button>

da ein Button sonst je nach HTML-Kontext als Submit-Button wirken kann.

Eine eigene Speichern-Schaltfläche ist normalerweise nicht erforderlich. Die WebAkte stellt die zentrale Speicherfunktion bereit.

MCDMS-Action

Eine konfigurierte MCDMS-Action wird beispielsweise so ausgelöst:

<button type="button"
        data-mcdms-action="DRUCKEN">
    Drucken
</button>

Die eigentliche Zuordnung des Scripts erfolgt ausschließlich in der Formular-Konfiguration.

Detailfelder

Detailfelder besitzen kein name und kein data-field, sondern:

<input type="text"
       data-detail-field="MEDIKAMENT">

Beispiel einer Detailzeile:

<template data-mcdms-detail-row>
    <tr>
        <td>
            <input type="text"
                   data-detail-field="MEDIKAMENT">
        </td>
        <td>
            <input type="text"
                   data-detail-field="DOSIERUNG">
        </td>
        <td>
            <input type="checkbox"
                   data-detail-field="BEDARF">
        </td>
    </tr>
</template>

Die aktuelle Implementierung verwendet genau ein gemeinsames template[data-mcdms-detail-row]. Reale Medikationsformulare nutzen dieses Muster bereits. MEDIKATIONSPLAN(1)

Detail-Liste

Der Bereich, in den Detailzeilen eingefügt werden, wird mit data-mcdms-detail-list markiert:

<tbody data-mcdms-detail-list>
</tbody>

Es können mehrere statische Detailbereiche vorhanden sein:

<tbody data-mcdms-detail-list
       data-bereich="REGEL">
</tbody>

<tbody data-mcdms-detail-list
       data-bereich="BEDARF">
</tbody>

Die fachliche Zuordnung zusätzlicher Bereiche erfolgt durch das Formular-JavaScript. Das Core-Verfahren interessiert nur data-mcdms-detail-list.

LIST-Datensätze

Bei RecordView=LIST verwendet eine Liste:

<tbody data-mcdms-record-list="AUFNAHME"
       data-filter-field="DIAGTYP"
       data-filter-value="2">
</tbody>

Eine einzelne Listenzeile wird über das gemeinsame Template beschrieben:

<template data-mcdms-record-row>
    <tr>
        <td>
            <span data-mcdms-record-order></span>
        </td>

        <td>
            <input type="text"
                   data-record-field="DIAGNOSE">
        </td>

        <td>
            <input type="text"
                   data-record-field="ICD">
        </td>

        <td>
            <input type="checkbox"
                   data-record-field="FREIGABE">
        </td>
    </tr>
</template>

Die Diagnosemaske verwendet genau dieses Prinzip mit data-mcdms-record-list, data-record-field und data-mcdms-record-order. Diagnosen(4)

LIST-Schaltflächen

Standardaktionen für LIST-Zeilen:

<button type="button"
        data-mcdms-record-move-up>
    ▲
</button>

<button type="button"
        data-mcdms-record-move-down>
    ▼
</button>

<button type="button"
        data-mcdms-record-duplicate>
    📋
</button>

<button type="button"
        data-mcdms-record-delete>
    ✕
</button>

Zeile hinzufügen

<button type="button"
        data-mcdms-record-add="AUFNAHME">
    + Diagnose hinzufügen
</button>

JavaScript setzt Feldwerte

Werden Werte per JavaScript geändert, sollten anschließend input und change ausgelöst werden:

const field = document.querySelector(
    '[name="STATUS"][data-field="STATUS"]'
);

field.value = "A";

field.dispatchEvent(
    new Event("input", { bubbles: true })
);

field.dispatchEvent(
    new Event("change", { bubbles: true })
);

Das ist insbesondere wichtig, damit die WebAkte Änderungen korrekt erkennt.

JavaScript nach partiellem Speichern

Nach einem Speichern kann der Formularinhalt partiell neu aufgebaut werden. Formular-JavaScript muss deshalb:

  • event-delegiert oder
  • idempotent

implementiert werden.

Nicht davon ausgehen, dass einmal gebundene DOM-Elemente dauerhaft bestehen bleiben.

Externe Abhängigkeiten

HTML-Formulare sollten grundsätzlich ohne zwingende externe CDN-Abhängigkeiten funktionieren.

Beispielsweise nicht voraussetzen:

<script src="https://..."></script>

Die WebAkte arbeitet mit restriktiven Browser-Sicherheitsregeln und stellt keinen allgemeinen externen CDN-Zugriff bereit. PROJECT-HANDOVER

Kurzregel für Konverter

Für automatisch erzeugte HTML-Formulare kann man sich im Wesentlichen an diese Zuordnung halten:

Masterfeld:
name="FELD"
data-field="FELD"

reines Anzeigefeld:
kein name

Detailfeld:
data-detail-field="FELD"

LIST-Feld:
data-record-field="FELD"

normaler Button:
type="button"

Kurz zusammengefasst:

eigenes Formular-Root für CSS-Kapselung

keine globalen CSS-Regeln

native HTML-Typen verwenden

name und data-field bei Masterfeldern identisch

reine Anzeigeelemente ohne name

Detailfelder über data-detail-field

1..n statische data-mcdms-detail-list

genau ein gemeinsames data-mcdms-detail-row-Template

LIST über data-mcdms-record-*

keine eigene Save-Schaltfläche erforderlich

normale Buttons immer type="button"

JavaScript event-delegiert oder idempotent

input/change nach JavaScript-Wertänderungen auslösen

responsive Gestaltung

keine zwingenden externen CDN-Abhängigkeiten

Formular darf Shell-CSS nicht beeinflussen