Web Components/template

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
Web Components Logo

Das template-Element ermöglicht es, Template-Vorlagen als Inhaltsfragmente im HTML-Dokument anzugeben, die zwar auf ihre Richtigkeit geparst, aber nicht gerendert werden. Erst wenn sie benötigt werden, können sie mit appendChild() in den Elementbaum eingehängt werden. [1] [2]

Sie sind eine gute Alternative zum zeitaufwendigen Nachladen von Inhalten mit AjaX oder dem dynamischen Erzeugen mit createElement, das bei komplexeren HTML-Strukturen schnell unbequem und unübersichtlich wird. Eric Bidelman stellt in diesem Artikel die Vorgängervorgehensweisen „Offscreen DOM“ und „Overloading Script“ und ihre Nachteile vor.

Template als Vorlage
<template id="zusatz">
  <h1>Überschrift</h1>
  <p>Textabsatz</p>
</template>

Wichtige Eigenschaften von Templates:

  • Das template-Element ist Teil des Dokuments, sein Inhalt hingegen nicht. Deshalb ist der Inhalt nicht sichtbar. Er wird vom Browser beim Laden der Seite zwar geparsed, dann aber zunächst „beiseite gelegt“. Der Zugriff auf den Inhalt mit DOM-Suchfunktionen wie document.getElementById() oder querySelector() ist nicht möglich.
  • Deshalb beeinträchten Template die Ladezeit einer Seite nur unwesentlich. Scripte, Bilder oder andere Mediendateien im Template bleiben unberücksichtigt, bis das Template verwendet wird.
  • Templates können überall im head oder body notiert werden und können beliebigen Inhalt haben. template kann auch Nachfahrenelement von table oder select sein, die sonst nur festgelegte Kindelemente haben.
  • Der Inhalt eines Templates ist nur insoweit festgelegt, als dass dieser Inhalt an der Stelle, wo Sie ihn verwenden möchten, zulässig sein muss. Beispielsweise ist ein p-Element nicht als Kindelement eines span-Elements zulässig, deshalb dürfen Sie ein Template, das p Elemente enthält, nicht in ein span-Element einfügen. Es mag zwar im DOM nachher so im DOM vorliegen, aber es wird nicht wie erwartet dargestellt, weil das Inhaltsmodell verletzt wurde.

Um den Inhalt eines Templates zu verwenden, benötigen Sie JavaScript.

Feature-Erkennung

Generell ist eine Feature-Erkennung für das template-Element heute nicht mehr erforderlich, es wird seit über 10 Jahren von allen Browsern unterstützt.

Sollten Sie Bedarf an einem Fallback für Alt-Browser haben, können Sie so vorgehen:

Feature-Erkennung
function supportsTemplate() {
  return 'content' in document.createElement('template');
}

if (supportsTemplate()) {
  // Perfekt!
} else {
  // Verwende Polyfill
}

Es gibt einen einfachen Polyfill[3], der Inhalte von template-Elementen aus dem DOM entfernt. Nachteilig ist, dass er – je nach Seitengestaltung – zu einem kurzen Aufblitzen der Template-Inhalte führen kann und auch nicht die Ausführung von Scripten in Templates verhindert.

Wenn Sie Alt-Browser unterstützen müssen, ist es einfacher, auf das Template-Element zu verzichten und generell einen anderen Weg zu nutzen. Sie können HTML-Fragmente beispielseweise mit JavaScript zusammenbauen oder mittels AjaX vom Server erzeugen lassen.

Anwendungsbeispiel

In einer Webseite sollen alle angebotenen Waren in einer Tabelle aufgelistet werden. Die verfügbaren Waren sind in einem JavaScript-Array gespeichert (das beispielsweise per AjaX vom Server geholt worden sein kann). Für jeden Posten soll eine neue Tabellenzeile erzeugt werden.

Template anlegen

Unsere Seite besteht aus einer (noch) leeren Tabelle und dem Template.

Einbinden des Templates ansehen …
    <table id="angebotsliste">
      <thead>
        <tr>
          <th>Produkt</th>
          <th>Anzahl</th>
          <th>Preis</td>
        </tr>
      </thead>
      <tbody>
        <!-- Platz zum Einfügen der Tabellenzeilen -->
      </tbody>
    </table>
    <button name="aktualisieren">Aktualisieren</button>
    <template id="neueReihe">
      <tr>
        <td></td>
        <td></td>
        <td></td>
      </tr>
    </template>

Im Markup wird eine Tabelle mit Kopf, aber ohne weitere Inhaltselemente im body notiert.
Darunter befindet sich ein Aktualisieren-Button und das template mit der id neueReihe. Es besteht aus einer Tabellenzeile (tr) mit mehreren Tabellenzellen (td).

Ruft man diese Seite ab, wird nur die leere Tabelle und der (funktionslose) Button angezeigt. Das Template wird nicht dargestellt.

Template einbinden

Um den Templateinhalt zu verwenden, sind drei Schritte erforderlich:

  • Suchen des Templates im DOM und kopieren seines Inhalts
  • Füllen des Template-Inhalts mit Inhalten, soweit erforderlich
  • Einfügen des fertigen Inhalts ins DOM.

Der Template-Inhalt ist als DocumentFragment-Objekt in der Eigenschaft content des Template-Objekts zu finden. Dieses Objekt ist nicht im DOM, sondern ist über die content-Eigenschaft sozusagen in einer Extradimension des DOM versteckt. Um es zu kopieren, ist eigentlich die cloneNode-Methode vorgesehen, die jeder DOM-Knoten besitzt. Übergibt man ihr true als Parameter, kopiert cloneNode nicht nur den DocumentFragment-Knoten selbst, sondern auch alle seine Kindknoten.

Einbinden eines Templates mit cloneNode
const vorlageElement = document.getElementById('vorlage-id');
const vorlage = vorlageElement.content.cloneNode(true);
// Vorlage ausfüllen
zielknoten.appendChild(vorlage);

In vielen Dokumentationen im Netz findet man aber auch eine alternative Methode:

Einbinden eines Templates mit importNode
const vorlageElement = document.getElementById('vorlage-id');
const vorlage = document.importNode.cloneNode(vorlageElement.content, true);
// Vorlage ausfüllen
zielknoten.appendChild(vorlage);

Die importNode-Methode ist eigentlich für das Übernehmen von Knoten aus anderen Dokumenten vorgesehen, funktioniert aber auch innerhalb des gleichen Dokuments und klont einfach den übergebenen Knoten.

In unserem Beispiel soll auf Knopfdruck die Tabelle aus dem Array aufgebaut werden, damit die Daten im Array angezeigt werden:

Einbinden des Templates ansehen …
function listeAusgeben() {
  const tbody = document.querySelector("#angebotsliste tbody"),
        vorlage = document.querySelector("#neueReihe");

  // Wäre ein Programmierfehler: Tabelle oder Template fehlen
  if (!tbody || !vorlage)
    throw new Error("Programmierfehler!");

  // Eventuell vorhandenen alten Tabelleninhalt entfernen
  tbody.innerHTML = "";

  // Angebotsliste durchgehen und alle Artikel in Tabelle auflisten
  for (const artikel of angebote) {
    // Neue Instanz der Vorlage erzeugen
    const neueZeile = document.importNode(vorlage.content, true);

    // Zellen befüllen
    const cells = neueZeile.querySelectorAll("td");
    cells[0].textContent = artikel.bezeichnung;
    cells[1].textContent = artikel.menge;
    cells[2].textContent = artikel.preis.toFixed(2);		

    // Gefüllte Vorlage der Tabelle hinzufügen
    tbody.appendChild(neueZeile);
  });
}

Für den Button haben wir einen click-Handler registriert, der die Funktion listeAusgeben() aufruft – für Details dazu schauen Sie bitte ins vollständige Beispiel.

Die Funktion sucht sich an Hand der Id das tbody-Element der Angebotsliste und das Template aus dem DOM heraus. Sind nicht beide vorhanden, bricht sie das Programm ab, denn das ist ein Programmierfehler. Die Feature Detection für Templates, die früher im Beispiel enthalten war, ist heute obsolet und wurde entfernt.

Wurden tbody und Template gefunden, wird der tbody zunächst geleert, weil die Tabelle komplett neu aufgebaut werden soll. Falls die Tabelle hunderte von Zeilen hätte, wäre dies ein Performanceproblem und man müsste eine Logik implementieren, die nur die Änderungen ins DOM überträgt. Wir wollen uns aber um Templates kümmern.

In einer For...of-Schleife wird für nun jeden vorhandenen Artikel mittels importNode der Template-Inhalt geklont, die Tabellenzellen herausgesucht und ihr textContent befüllt. Danach wird die erzeugte Zeile in die Artikeltabelle eingefügt.

verschachtelte Templates

Es ist möglich, Templates beliebig ineinander zu verschachteln.

verschachtelte Template
<template id="zusatz">
  <h1>Überschrift</h1>
  <p>Textabsatz</p>
  <template id="nochwas">
    <h1>Ergänzung</h1>
    <p>Textabsatz</p>
  </template>
</template>
Beachten Sie, dass das Aktivieren eines Templates eventuell darin befindliche Templates unberührt lässt. Diese müssen ebenfalls aktiviert werden.

Fazit

Mit dem template-Element können Sie noch nicht benötigte Teile der Seite bereits beim ersten Übertragen mitsenden und später aktivieren.

Dies können Meldefenster, Login-Formulare, Einstellungen-Dialoge etc. sein, die bei Bedarf aus dem template-Markup erstellt werden, um den Dialog nicht erst direkt vom Server laden zu müssen, also HTTP-Requests einzusparen, und letztlich schneller verfügbar zu sein.

Auch beim Lazy Loading (engl. etwa „faules ..“ oder „müßiges Laden“), einem Entwurfsmuster, bei dem Datenobjekte grundsätzlich Werte oder andere, abhängige Objekte bereitstellen, diese aber erst bei einer konkreten Anfrage aus der Datenquelle holen, ist das Verwenden von template sinnvoll.[4]

Siehe auch

Weblinks

  1. W3C: The template element
  2. MDN: template
  3. Jeff Carpenter bei Github: Polyfill für <template>
  4. Wikipedia: Lazy Loading