Direktiven sind ein mächtiges Werkzeug bei der Entwicklung mit Angular, um diverse Problemstellungen generisch und wiederverwendbar zu implementieren. Ein Feature, welches genau diese Idee unterstützt und zumindest für “standalone-Komponenten” verwendet werden kann, ist die Directive Composition API. Hier lassen sich grob zwei Anwendungsfälle unterscheiden
a) eine Komponente soll immer eine bestimmte Direktive erhalten
@Component({
selector: 'app-directive-composition',
standalone: true,
imports: [MatTooltip],
hostDirectives: [
MatTooltip
],
templateUrl: './directive-composition.component.html',
styleUrl: './directive-composition.component.scss'
})
export class DirectiveCompositionComponent {
constructor(private matTooltip: MatTooltip) {
matTooltip.message = 'Component ToolTip'
}
}
Unsere Komponente erhält damit nun automatisch die in hostDirective deklarierten Direktiven und kann sich diese im Konstruktor injizieren lassen. Ohne dieses Vorgehen müsste bei jeder Verwendung dieser Komponente sichergestellt werden, dass die Direktive auf dem Host deklariert ist:
<app-directive-composition mat-tooltip>
b) eine Direktive soll eine bestehende Direktive (oder mehrere) erweitern
Ein typisches Beispiel wäre folgendes: ein Mat-Tooltip soll angezeigt werden, aber generell nur unter bestimmten Bedingungen (z.B. nur, wenn er wirklich benötigt wird, der Inhalt also abgeschnitten wird). Anstatt nun bei jeder Verwendung eine entsprechende Prüfung per Property ([matTooltipDisabled]) zu setzen erlaubt uns die Directive Composition eine “Komposition” zu erstellen, also eine eigene Direktive die, ähnlich wie bei der Komponente oben, automatisch andere Direktiven instanziiert und an den Host bindet
@Directive({
selector: '[appShowToolTipIfTruncated]',
standalone: true,
host: {
'[style.white-space]': '"nowrap"',
'[style.overflow]': '"hidden"',
'[style.text-overflow]': '"ellipsis"'
},
hostDirectives: [MatTooltip]
})
export class ShowToolTipIfTruncatedDirective implements AfterViewChecked {
constructor(private el: ElementRef, private matTooltip: MatTooltip) {
}
ngAfterViewChecked() {
const textContent = this.el.nativeElement.textContent;
this.matTooltip.message = textContent;
this.matTooltip.disabled = this.calculateTextContentWith() < this.el.nativeElement.clientWidth;
}
private calculateTextContentWith(): number {
const elementStyle = getComputedStyle(this.el.nativeElement);
const canvas = document.createElement('canvas') as HTMLCanvasElement;
const context = canvas.getContext('2d');
context!.font = elementStyle.getPropertyValue('font');
return context!.measureText(this.el.nativeElement.innerHTML).width;
}
}
Eine tolle weitere Möglichkeit wiederverwendbaren und gut wartbaren Code zu schreiben.
Code? Hab’ ich. github.com/GEDOPLAN/ng16-ng17