Directives are classes that add behavior to elements in your Angular templates. There are three categories: components (directives with a template), attribute directives (change appearance or behavior of an element), and structural directives (change the DOM layout by adding or removing elements).
Attribute directives modify the appearance or behavior of an element. Angular provides built-in attribute directives and you can create custom ones.
Add or remove multiple CSS classes dynamically:
<div [ngClass]="{
'highlight': isHighlighted,
'error': hasError,
'disabled': isDisabled
}">Conditional classes</div>
Set multiple inline styles dynamically:
<div [ngStyle]="{
'color': textColor,
'font-size': fontSize + 'px',
'background': bgColor
}">Dynamic styles</div>
Create a custom directive using the @Directive decorator:
import { Directive, ElementRef, Renderer2, HostListener, HostBinding } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
@HostBinding('style.backgroundColor') bgColor = 'transparent';
constructor(private el: ElementRef, private renderer: Renderer2) { }
@HostListener('mouseenter') onMouseEnter() {
this.bgColor = 'yellow';
this.renderer.setStyle(this.el.nativeElement, 'fontWeight', 'bold');
}
@HostListener('mouseleave') onMouseLeave() {
this.bgColor = 'transparent';
this.renderer.setStyle(this.el.nativeElement, 'fontWeight', 'normal');
}
}
Use it in templates: <p appHighlight>Hover over me!</p>.
Structural directives change the structure of the DOM by adding, removing, or manipulating elements. They are prefixed with an asterisk * in templates, which is syntactic sugar for an <ng-template> wrapper.
Conditionally include a template based on a boolean expression:
<div *ngIf="isLoggedIn; else loginPrompt">
Welcome, {{ username }}!
</div>
<ng-template #loginPrompt>
<p>Please log in.</p>
</ng-template>
Iterate over a collection and render a template for each item:
<ul>
<li *ngFor="let user of users; let i = index; trackBy: trackByUserId">
{{ i + 1 }}. {{ user.name }}
</li>
</ul>
Local variables available: index, first, last, even, odd, count.
trackBy with ngFor when working with large lists. It helps Angular identify which items changed, improving rendering performance by avoiding unnecessary DOM manipulations.Switch between multiple conditional templates:
<div [ngSwitch]="role">
<p *ngSwitchCase="'admin'">Admin Panel</p>
<p *ngSwitchCase="'editor'">Content Editor</p>
<p *ngSwitchCase="'viewer'">Read Only</p>
<p *ngSwitchDefault>Unknown role</p>
</div>
Create your own structural directive using TemplateRef and ViewContainerRef:
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appRepeat]'
})
export class RepeatDirective {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) { }
@Input() set appRepeat(times: number) {
this.viewContainer.clear();
for (let i = 0; i < times; i++) {
this.viewContainer.createEmbeddedView(this.templateRef);
}
}
}
Usage: <p *appRepeat="5">Repeated paragraph</p>.
Structural directives use microsyntax — a compact language for expressing template logic. The *ngFor="let item of items; let i = index" is shorthand that Angular desugars into <ng-template ngFor let-item="$implicit" [ngForOf]="items" let-i="index">.
This chapter covered attribute directives (ngClass, ngStyle, custom) and structural directives (ngIf, ngFor, ngSwitch, custom). You learned how to use ElementRef, Renderer2, @HostListener, @HostBinding, TemplateRef, ViewContainerRef, and microsyntax to build powerful, reusable behavior.
appTooltip that shows a tooltip on hover with a configurable text and position (top, bottom, left, right). Include a fade-in animation using Renderer2. Then build a custom structural directive appPermission that conditionally renders content based on a user role string input.