Das ist Teil 5 unserer Reihe Entwicklung von Reale-Welt-Anwendungen ohne Orientierungsverlust

von Richard Voß @richard_voss

Seit (vor-)letztem Jahr entwicklen wir in der WPS immer öfter Anwendungen für unsere Kunden mit Hilfe von Angular 4+. Angular ist ein populäres Framework (es wird auch als Plattform bezeichnet) zur Entwicklung von web-basierten Frond-Ends mit Typescript, HTML und CSS. Es ist Open Source Software und wird hauptsächlich durch Google vorangetrieben.

Das Framework macht es wesentlich einfacher, komplexe GUIs zu strukturieren, fördert die Wiederverwendung von Komponenten und – am wertvollsten – erlaubt es tatsächlich, testgetriebene Front-End-Entwicklung zu betreiben, die Spaß macht.

Trotz all dieser Großartigkeit des Frameworks bleiben genug Fehler übrig, die man machen kann. Wir haben einige erfolgreiche Muster aber auch Fallstricke gefunden und gesammelt.

Dieser Artikel gibt einen weiteren Einblick in unsere „Angular Pattern Library“. Beim letzten Mal ging es um die Vermeidung von Vererbung bei Komponenten. Heute beleuchten wir ganz kurz eine der dafür wichtigsten Techniken, um Templates besser zu modularisieren.

👍 Use Advanced Template Transclusion

Ohne Transklusion von Templates zu nutzen kann man Duplizierung von Templates nicht vermeiden.

Das Angular-Tutorial ist nicht sehr detailliert bei diesem Thema. <ng-content> wird z.B. so gut wie nicht erwähnt. Es lohnt sich, andere Quellen zu konsultieren, um die vollen Möglichkeiten auszuschöpfen. Ich will hier ein Schlaglicht auf eine dieser Möglichkeiten werfen.

Also wir versuchen nun, wie immer, Teile von Komponenten aus anderen herauszulösen, ohne in die Vererbungsfalle zu treten. Oft ist auffällig, dass es nicht immer nur um konkrete Bausteine der Oberfläche geht, sondern dass sich Strukturen wiederholen: “Kopf + Inhalt + Fußzeile” als wiederkehrender Aufbau, oder “Links + Rechts” für Vergleichsansichten, oder sehr beliebt “Beschriftung + Eingabefeld + Meldungen” bei Formularen. Das Markup und die Logik zwischen diesen Elementen nenne ich abstrakte Struktur und es ist sehr häufig immer das selbe (nicht nur zufällig gleich) und soll nicht wiederholt werden müssen.

Um eine solche abstrakte Struktur als Komponente zu realisieren, kann man <ng-content select="..."> verwenden. Allerdings hat sich herausgestellt, dass es eine mächtigere Möglichkeit gibt: <ng-template> und <ng-container> ermöglichen es, nicht einfach nur DOM-Knoten an andere Punkte zu verschieben, sondern tatsächlich Templates wie Parameter für eine Komponente zu nutzen.

@Component({
  selector: 'abstract-structure',
  template: `
    <header>
      <ng-container [ngTemplateOutlet]="top"></ng-container>
    </header>
    <aside>
      <ng-container [ngTemplateOutlet]="left"></ng-container>
    </aside>
    <div class="content">
      <ng-container [ngTemplateOutlet]="bottom"></ng-container>
    </div>`
})
export class AbstractStructureComponent {
  @ContentChild('top') top: TemplateRef<any>;
  @ContentChild('left') left: TemplateRef<any>;
  @ContentChild('bottom') bottom: TemplateRef<any>;
}

@Component({
  selector: 'concrete-structure',
  template: `
    <abstract-structure>
      <ng-template #left><a></a></ng-template>
      <ng-template #top><b></b></ng-template>
      <ng-template #bottom><c></c></ng-template>
    </abstract-structure>`
})
export class ConcreteStructureComponent {

}

Die Vorteile dieses Beispiels sind:

  1. Es entstehen weniger unnötige HTML-Elemente im resultierenden DOM. Das ist eine gute Nachricht für den CSS-Code.
  2. Die Tatsächliche Instanziierung des (Parameter-)Templates kann explizit gesteuert werden. Das kann die Performance klar verbessern, z.B. indem Templates, die abhängig von Bedingungen gar nicht sichbar sind, auch tatsächlich gar nicht instanziiert werden (also auch keine Change Detection brauchen).
  3. Es involviert zwar mehr Code, aber die Intention einer Komponente wird wesentlich klarer. Man kann @ContentChild('x') was wie @Input('x') lesen. So wird die Schnittstelle der abstrakten Struktur-Komponente auf den ersten Block offensichtlich, ohne dass man ihr Template lesen muss.

Weiter von hier…

Neben diesem Schlaglicht empfehle ich vertiefende und noch detailliertere Lektüre, denn mit  dem dynamischen Instanziieren von Templates (und Komponenten) öffnen sich ganz andere Möglichkeiten der Wiederverwendung von Angular-Komponenten.

Die Überschrift für den nächsten Artikel der Reihe steht diesmal noch nicht fest. Ich bin offen für Feedback und Anregungen.

 

 

 

Seriennavigation<< Angular @ WPS Teil 4: Komponenten sind schlechte Erben