---
title: DOCX-Template-Beispiele
description: Typische Aufbauten eines Word-Templates mit Befehlen, Schleifen und Bedingungen
---

Diese Seite zeigt typische Muster, wie ein Word-Template für flexiDok aufgebaut wird. flexiDok nutzt intern die Bibliothek [docx-templates](https://github.com/guigrpa/docx-templates) - die Befehlssyntax dieser Seite folgt ihrer Konvention.

Die Referenz aller Hilfsfunktionen (`getComponentListForAllSectionsByChapterName`, `createImage`, `formatDate`, …) finden Sie unter [DOCX-Template-Funktionen](/docx/docx-template-functions).

---

## Befehle im Überblick [#befehle-im-uberblick]

flexiDok verwendet **`+++`** als Befehls-Trennzeichen. Jeder Befehl steht zwischen zwei `+++`.

| Befehl | Bedeutung |
|---|---|
| `+++INS ausdruck+++` | Ergebnis eines Ausdrucks an der Stelle einfügen |
| `+++EXEC code+++` | JavaScript ausführen, nichts einfügen (für Variablendefinitionen, Vorverarbeitung) |
| `+++FOR x IN liste+++` … `+++END-FOR x+++` | Über eine Liste iterieren |
| `+++IF bedingung+++` … `+++END-IF+++` | Abschnitt nur bei erfüllter Bedingung einfügen |
| `+++IMAGE bildobjekt+++` | Bild einfügen |
| `+++LINK ({url, label})+++` | Hyperlink einfügen |

:::tip[Schleifenvariable mit `$`]
Innerhalb einer `FOR`-Schleife muss der Name der Schleifenvariable mit `$` präfixiert werden, z.B. `+++INS $eintrag.name.value+++`. Der zusätzliche Index des innersten Loops steht in `$idx` (0-basiert).
:::

---

## Typischer Aufbau eines Templates

Ein Report wird in der Regel so strukturiert:

1. **Vorbereitungsblock** am Anfang: Listen aufbauen, Konstanten setzen, Hilfsfunktionen definieren (ein bis mehrere `EXEC`-Befehle)
2. **Inhaltsteil**: Text mit `INS`, Tabellen mit `FOR`, bedingte Passagen mit `IF`

### 1. Vorbereitungsblock - Listen und Kennzeichen aufbauen [#1-vorbereitungsblock-listen-und-kennzeichen-aufbauen]

Am Anfang des Dokuments werden oft mehrere `EXEC`-Blöcke platziert, in denen Listen aus den Dokumentdaten gefiltert und kombiniert werden. Die Ergebnisse stehen danach im gesamten Template zur Verfügung.

```
+++EXEC
LISTE_A = getListFromChapterAndChapterType(`eintraege`, `TypA`);
LISTE_B1 = getListFromChapterAndChapterType(`eintraege`, `TypB`);
LISTE_B2 = getListFromChapterAndChapterType(`eintraege`, `TypB Variante`);
LISTE_B3 = getListFromChapterAndChapterType(`eintraege`, `TypB Variante Kombi`);

GESAMT_OHNE_KOMBI = [].concat(LISTE_B1, LISTE_B2);
GESAMT_ALLE      = [].concat(LISTE_B1, LISTE_B2, LISTE_B3);

IS_B1     = LISTE_B1.length > 0;
IS_B2     = LISTE_B2.length > 0;
IS_GESAMT = GESAMT_ALLE.length > 0;

SHOW_BLOCK = true;
if (LISTE_A.length == 0 && LISTE_B1.length == 0) {
  SHOW_BLOCK = false;
}
+++
```

:::note[Benennung von Variablen]
In unseren Templates nutzen wir für diese Template-weiten Variablen meist GROSSBUCHSTABEN - das macht sie im Text gut erkennbar und vermeidet Namenskollisionen mit Feldern aus dem Dokument.
:::

### 2. Tabellendaten aus mehreren Listen zusammensetzen

Ein häufiges Muster: Aus mehreren gefilterten Listen wird eine gemeinsame Tabelle aufgebaut, in der jede Zeile zusätzlich ein Kürzel und eine Beschreibung bekommt.

```
+++EXEC
TABELLE = [];

A_COUNT = 1;
for (let eintrag of LISTE_A) {
  let OBJ = {};
  OBJ[`KUERZEL`]    = ``;
  OBJ[`BESCHREIBUNG`] = ``;
  if (eintrag.ChapterTypes.length > 0 && eintrag.ChapterTypes[0] == `TypA`) {
    OBJ[`KUERZEL`]      = `A ` + A_COUNT;
    OBJ[`BESCHREIBUNG`] = `Beschreibung Typ A`;
    A_COUNT++;
    OBJ[`NUMMER`]    = eintrag.uebersicht.nummer.value + ` ` + eintrag.uebersicht.bezeichnung.value[0];
    OBJ[`KENNUNG`]   = eintrag.uebersicht.kennung.value;
    OBJ[`ZUSATZ`]    = eintrag.uebersicht.zusatz.value;
    TABELLE.push(OBJ);
  }
}

B_COUNT = 1;
for (let eintrag of LISTE_B1) {
  let OBJ = {};
  OBJ[`KUERZEL`]      = `B ` + B_COUNT;
  OBJ[`BESCHREIBUNG`] = `Beschreibung Typ B`;
  B_COUNT++;
  OBJ[`NUMMER`]    = eintrag.uebersicht.nummer.value + ` ` + eintrag.uebersicht.bezeichnung.value[0];
  OBJ[`KENNUNG`]   = eintrag.uebersicht.kennung.value;
  OBJ[`ZUSATZ`]    = eintrag.uebersicht.zusatz.value;
  TABELLE.push(OBJ);
}
+++
```

Diese `TABELLE` kann später im Template mit einer einzigen `FOR`-Schleife in eine Word-Tabelle geschrieben werden.

### 3. Hilfsfunktionen inline definieren

Für kleine, wiederverwendbare Logik lassen sich JavaScript-Funktionen direkt im Template definieren:

```
+++EXEC
ABSCHNITTE = getComponentListForAllSectionsByChapterName(`kapitelname`);

getAbschnittsbezeichnung = (arr) => {
  for (let tmp of arr) {
    if (tmp.Name === `uebersicht`) {
      return tmp.nummer.value + ` ` + tmp.bezeichnung.value;
    }
  }
}
+++
```

Die Funktion `getAbschnittsbezeichnung(...)` kann anschließend überall im Template aufgerufen werden.

### 4. Konstanten und Textbausteine

Feste Texte, die an mehreren Stellen vorkommen, werden einmal definiert und wiederverwendet:

```
+++EXEC
OK_TEXT      = `bestanden`;
NOK_TEXT     = `nicht bestanden (siehe Punkt 2)`;
IO_TEXT      = `in Ordnung`;
NIO_TEXT     = `nicht in Ordnung (siehe Punkt 2)`;
MINUS_TEXT   = `-`;
HINWEIS_TEXT = `nach Herstellerangaben`;
+++
```

### 5. Statusflag anhand einer Liste setzen

`EXEC` lässt sich auch in einer `FOR`-Schleife verwenden, um z.B. ein einziges Statusflag zu setzen, wenn in einer Liste mindestens ein bestimmtes Kriterium zutrifft:

```
+++EXEC
NOTIZEN    = getComponentListForAllSectionsByChapterName(`notizen`);
ZEIGE_ERFOLG = true;
+++

+++FOR notiz IN NOTIZEN+++
+++EXEC
if ($notiz.anzeigen.value) {
  ZEIGE_ERFOLG = false;
}
+++
+++END-FOR notiz+++
```

Nach diesem Block steht `ZEIGE_ERFOLG` für den Rest des Templates als Flag zur Verfügung.

---

## Inhaltsmuster im Fließtext [#inhaltsmuster-im-flietext]

### Bedingter Text mit `IF`

Typischer Aufbau für *"Alles ok"* vs. *"Abweichungen"*:

```
+++IF ZEIGE_ERFOLG+++
Die +++INS allgemein.prozessdaten.dokumenttyp.value+++ war erfolgreich, es wurden keine Abweichungen festgestellt.
+++END-IF+++

+++IF !ZEIGE_ERFOLG+++
Die +++INS allgemein.prozessdaten.dokumenttyp.value+++ war erfolgreich, es wurden aber Abweichungen festgestellt. Die Prüfung gilt erst als abgeschlossen, wenn dokumentierte Nachweise zu deren Behebung vorliegen. Folgende Abweichungen wurden festgestellt:

+++FOR notiz IN NOTIZEN+++
+++IF $notiz.anzeigen.value+++
•    +++INS $notiz.titel.value+++
+++END-IF+++
+++END-FOR notiz+++

Detaillierte Beschreibungen befinden sich unter Punkt 2.
+++END-IF+++
```

:::note[`!` vor dem Ausdruck]
`+++IF !ZEIGE_ERFOLG+++` funktioniert wie in JavaScript: der Block wird eingeschlossen, wenn `ZEIGE_ERFOLG` falsch/leer ist.
:::

### Varianten nach Feldwert

Unterschiedlicher Text je nach Wert eines Dokumentfelds:

```
+++IF allgemein.prozessdaten.dokumenttyp.value === `Variante1`+++
Erläuterungstext für Variante 1.
+++END-IF+++

+++IF allgemein.prozessdaten.dokumenttyp.value !== `Variante1`+++
Erläuterungstext für alle anderen Varianten.
+++END-IF+++
```

:::tip[Vergleichsstrings in Backticks]
Wir verwenden in Template-Ausdrücken durchgehend **Backticks** (`` ` ``) für Strings statt einfache oder doppelte Anführungszeichen. Grund: Word ersetzt normale Anführungszeichen gerne durch typografische Smart Quotes (`„ "`), die dann zu Syntaxfehlern führen. Backticks werden von Word nicht autokorrigiert.
:::

### Einfache Wertausgabe

```
Auftragsnummer: +++INS allgemein.kopf.auftragsnummer.value+++
Kunde:          +++INS allgemein.kunde.name.value+++
Erstellt am:    +++INS formatDate(allgemein.dokumentation.datum.value, `dd.MM.yyyy`)+++
Geprüft durch:  +++INS getValidator(true)+++
```

### Tabellenzeile per Schleife

Die `FOR`-Schleife funktioniert auch über Tabellenzeilen: Der `FOR`-Befehl steht in der ersten Zeile (als Kommentarzeile), die eigentliche Inhaltszeile folgt, und `END-FOR` steht in einer abschließenden Zeile.

```
| Kürzel                    | Nummer                  | Kennung                |
|---------------------------|-------------------------|------------------------|
| +++FOR z IN TABELLE+++    |                         |                        |
| +++INS $z.KUERZEL+++        | +++INS $z.NUMMER+++       | +++INS $z.KENNUNG+++     |
| +++END-FOR z+++           |                         |                        |
```

Word löscht die Zeilen mit `FOR` und `END-FOR` automatisch - übrig bleibt nur die Inhaltszeile, einmal pro Listen-Eintrag.

### Bilder einfügen [#bilder-einfugen]

```
+++FOR bild IN allgemein.fotos.bilder+++
+++IMAGE createImage($bild, 10, 7, null, true, true)+++
+++END-FOR bild+++
```

Oder eine PDF-Anlage seitenweise:

```
+++FOR seite IN createPDFPages(allgemein.anhang.zertifikat)+++
+++IMAGE $seite+++
+++END-FOR seite+++
```

---

## Vollständiges Miniatur-Beispiel [#vollstandiges-miniatur-beispiel]

Ein knappes, komplettes Template mit Vorbereitung, bedingter Ausgabe und Tabelle:

```
+++EXEC
ABSCHNITTE = getComponentListForAllSectionsByChapterName(`notizen`);
HAT_ABWEICHUNG = false;
+++

+++FOR a IN ABSCHNITTE+++
+++EXEC
if ($a.anzeigen.value) { HAT_ABWEICHUNG = true; }
+++
+++END-FOR a+++

Prüfbericht für +++INS allgemein.kunde.name.value+++
Datum: +++INS formatDate(allgemein.kopf.datum.value, `dd.MM.yyyy`)+++

+++IF !HAT_ABWEICHUNG+++
Keine Abweichungen festgestellt.
+++END-IF+++

+++IF HAT_ABWEICHUNG+++
Folgende Abweichungen wurden festgestellt:
+++FOR a IN ABSCHNITTE+++
+++IF $a.anzeigen.value+++
•    +++INS $a.titel.value+++
+++END-IF+++
+++END-FOR a+++
+++END-IF+++

Geprüft durch: +++INS getValidator(true)+++
```

---

## Tipps aus der Praxis

- **Backticks statt Anführungszeichen** in allen JavaScript-Ausdrücken (siehe Hinweis oben).
- **Template-Variablen in GROSSBUCHSTABEN** - leichter lesbar und kollidieren nicht mit Feldnamen.
- **Vorbereitungsblöcke ganz an den Anfang** setzen; Inhaltsblöcke sollten sich auf fertige Variablen stützen, nicht mehrere `getListFromChapter…`-Aufrufe mit denselben Argumenten wiederholen.
- **`EXEC`-Blöcke erzeugen keine Leerzeilen** - aber der umgebende Absatz im Word bleibt. Platzieren Sie `EXEC`-Blöcke daher in eigenen Absätzen, die später gelöscht werden können, oder inline in bestehende Absätze.
- **Fehlt ein Feld im Dokument**, ist der Ausdruck `kapitel.abschnitt.feld.value` `undefined`. Wenn das ein Problem ist, prüfen Sie vorher per `IF`:

```
+++IF allgemein.kunde.name && allgemein.kunde.name.value+++
Kunde: +++INS allgemein.kunde.name.value+++
+++END-IF+++
```

- **Smart Quotes in Word deaktivieren** für Template-Dateien: *Datei → Optionen → Dokumentprüfung → AutoKorrektur-Optionen → AutoFormat während der Eingabe → "Gerade Anführungszeichen" deaktivieren.* Andernfalls wandelt Word `"foo"` in `„foo"` um - und JavaScript-Ausdrücke brechen.
