Nach oben

Host-Element-Probleme in Angular

Angular-Komponenten haben immer ein Host-Element. Das ist ein Pseudo-HTML-Tag mit dem Selektor-Name der Komponente. Dieses Host-Element ist insbesondere bei Listen problematisch für die Semantik des HTML. Eine Anleitung zur Sicherstellung von semantisch korrekt verpacktem HTML.

Host-Element als Pseudo-HTML-Tag

Wenn Sie eine Angular-Komponente einbinden, wird diese im generierten HTML in einem Host-Element aufgeführt. Dieses Host-Element fungiert als Klammer um das komponentenspezifische HTML und trägt die Bezeichnung, welche als Selektor festgelegt wurde.

Eine Komponente hat einen bestimmten Selektor, der im @Component-Dekorator angegeben wird:

@Component({
   selector: 'test-name',
   template: '<div>Dummy content</div>', 
   styleUrls: [ './test-name.component.scss']
})
exportclassTestNameComponent{ … }

Wenn die Komponente z.B. direkt im HTML der AppComponent eingebunden wird, wird dafür ein Pseudo-HTML-Tag mit dem Selektor der Komponente eingesetzt:

<test-name></test-name>

Dieses Pseudo-HTML-Tag ist dann auch im HTML der Applikation so ersichtlich:

<app-root>
   …
   <test-name>
      <div>Dummy content</div>
   </test-name>
   …
</app-root>

Dieses zusätzliche HTML-Element können Sie mit CSS-Styles ergänzen (im CSS/SCSS der Komponente):

:host {
   display: block
}

Host-Element und semantisches HTML

Diese Angular-Eigenheit verursacht meist keine Schwierigkeiten, da die Browser mit diesen Pseudo-HTML-Tags umgehen können und da Sie diese Elemente auch mit Stilregeln ergänzen können. Es gibt aber Fälle, in denen die Semantik des HTMLs durch dieses Host-Element beeinträchtigt wird, wenn keine entsprechende Vermeidungsmassnahme ergriffen wird.

Listen stellen ein Beispiel für den etwas umständlichen Umgang mit diesen Host-Elementen dar. Um ein semantisch stimmiges HTML zu erhalten, führen Sie die Listen-Tags (<li>) direkt innerhalb der Listen-Tags (<ul>, <ol>) auf.

Sollen die Liste und die Listen-Elemente wiederverwertbar sein, bietet es sich an, für beide eine Komponente zu erstellen (z.B. ListComponent, ListItemComponent). Damit die ListComponent flexibel befüllt werden kann, nehmen Sie sinnvollerweise nur das Listen-Tag und einen Füllbereich (ng-content) hinein:

<!-- list-component.component.html -->
<ul>
   <ng-content><!-- list content goes here --></ng-content>
</ul>

In der AppComponent (oder an anderer Stelle) wird dann die Liste mit den beiden Komponenten zusammengebaut , z.B. unter Verwendung einer „For“-Schlaufe im Template:

<list>
   <list-item *ngFor="let item of items"></list-item>
</list>

Das generierte HTML führt dann jeweils innerhalb des ul-Tags zuerst das Host-Element der Listen-Elemente anstelle des li-Tags auf:

<list>
   <ul>
      <list-item>
         <li>…</li>
      </list-item>
   <ul>
</list>

Um aber sicherzustellen, dass direkt innerhalb eines ul-Tags nur li-Tags vorhanden sind, nehmen Sie entsprechend das li-Tag aus der ListItemComponent heraus. An jeder Stelle, an der die ListComponent verwendet wird, müsste also folgendes gemacht werden:

<list>
   <li *ngFor="let item ofitems">
      <list-item></list-item>
   </li>
</list>

Das li-Tag ist nun aber weder Teil der List- noch der ListItemComponent. Trotzdem können Sie über «ng-deep» mit Stilregeln ergänzen (im CSS der ListComponent), wobei «ng-deep» aber als veraltet gilt (siehe Angular Guide: Component Styles):

ul::ng-deep> li {
   border-bottom: 1px solid black;
}

Konklusion

Host-Elemente sind meist unproblematisch, können aber bei falscher Verwendung die HTML-Semantik gefährden. Der beschriebene Weg für die Darstellung von Listen mag zwar etwas unschön sein, aber Sie halten so die Semantik ein, da das benötigte li-Tag weder der List- noch der ListItemComponent zugehörig ist.

Dieser Artikel ist Teil unserer Serie über Stärken und Schwächen von Angular.

Kommentare

Kommentar schreiben

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert