kdocs
GitHub
Lang - Web
Lang - Web
  • Base
    • Css
    • Javascript
    • Typescript
      • New Project
  • Frameworks
    • Angular
      • Directives
      • Components
      • Templates
        • Bindings
        • Control Flow
        • Variables
      • Signals
      • Pipes
      • Services
        • Dependency Injection
      • Forms
        • Reactive Form
        • Template-Driven Form
      • Router
      • HTTP Client
      • Observables RxJS
      • Testing
        • Components
        • Directives
        • Pipes
        • Services
      • Optimization & Performance
      • Security
Powered by GitBook
On this page
  • About
  • Generate Directive (CLI)
  • Best Practices
  • Attribute Directives
  • Built-in Attribute Directives
  • Building an Attribute Directive
  • Structural Directives
  • Built-in Structural Directives
  • Building a Structural Directive
  • Adding Directives to a Component with hostDirectives
  • Including inputs and outputs
  • Adding Directives to other Directives with hostDirectives
  1. Frameworks
  2. Angular

Directives

PreviousAngularNextComponents

Last updated 5 months ago

About

They are classes that add additional behavior to elements in your applications.

Use Angular's built-in directives to manage forms, lists, styles and what users see.

#components are type of directive that have Templates.

ng g directive [directive-name] [options]

Best Practices

  • Avoid changing elements directly through the DOM like *.nativeElement.style.*, since angular is able to render the Templates without a DOM, for instance when using service workers, then these properties may not be available.

Attribute Directives

Change the appearance or behavior of an element, component, or another directive.

They listen to and modify the behavior of other HTML elements, attributes, properties, and components.

Built-in Attribute Directives

Built-in directives use only public APIs.

They do not have special access to any private APIs that other directives can't access.

NgClass

An old way of adding and removing CSS classes in elements.

@Component({
    template: `
        <!-- Adding 'special' class based on 'isSpecial' value -->
        <div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>

        <!-- Adding multiple classes with object 'multipleClasses', where each key is the class that will be applied based on its value -->
        <div [ngClass]="multipleClass">Div of multiple classes</div>
    `
})
export class Component {
    protected isSpecial = true;

    protected multipleClasses = {
        'className1': true,
        'className2': false,
    }
}

NgStyle

An old way of adding and removing HTML styles in elements.

@Component({
    template: `
        <!-- Adding single inline style -->
        <div [ngStyle]="'font-size': true ? '10px' : '20px'">This div is special</div>

        <!-- Adding multiple classes with object 'multipleClasses', where each key is the class that will be applied based on its value -->
        <div [ngStyle]="multipleStyles">Div of multiple classes</div>
    `
})
export class Component {
    protected isSpecial = true;

    // You may use regular style names, or camelCase names without quotes
    protected multipleStyles = {
        'font-weight': true ? 'bold': 'normal',
        fontSize: false ? '10px' : '20px',
    }
}

NgModel

Use it to display a data property and update that property when the user makes changes. (Adds two-way data binding to HTML form elements)

<label for="example-ngModel">[(ngModel)]:</label>
<input [(ngModel)]="currentItem.name" id="example-ngModel">
<input [ngModel]="currentItem.name" (ngModelChange)="setUppercaseName($event)" id="example-uppercase">

To apply [(ngModel)] to a non-form built-in element or a thid-party custom component, you have to write a value accessor.

By default a directive will have a [appDirective] attribute seletor, but it could be a class or component selector as well.

Inject ElementRef to get access to the host DOM element.

@Directive({
    standalone: true,
    selector: "[appNew]",
})
export class NewDirective {
    // Inject the `ElementRef` to get the reference to the Host DOM element
    constructor(private el: ElementRef) {
        this.el.nativeElement.style.backgroundColor = "yellow";
    }
}
<p appNew>This will have yellow background.</p>

Passing values into an attribute directive

Pass values to the Directive with input() using the same selector name as the variable name.

export class NewDirective {
    // This uses the same variable name as the directive's selector
    appNew = input("yellow");

    constructor(private el: ElementRef) {
        this.el.nativeElement.style.backgroundColor = this.appNew;
    }
}
<p [appNew]="white">This will override the color to white.</p>

Handling user events

You can handle user events or subscribe to event of the DOM with @HostListener().

export class NewDirective {
    constructor(private el: ElementRef) {}

    @HostListener("mouseenter") onMouseEnter() {
        this.highlight(true);
    }

    @HostListener("mouseleave") onMouseLeave() {
        this.highlight();
    }

    private highlight(state = false) {
        this.el.nativeElement.style.backgroundColor = state ? "yellow" : "transparent";
    }
}

Structural Directives

Change the DOM layout by adding and removing DOM elements.

Structural directives can be raw applied to <ng-template> only.

<ng-template [ngIf]=""><p>Paragraph</p></ng-template>
<ng-template newStructuralDirective let-item [selectFrom]="items">
    <p>Paragraph</p>
</ng-template>

Angular expanded the use of them to other HTML elements by the use of shorthand syntax (*).

<p *ngIf="">Paragraph</p>
<p *newStructuralDirective="let item from items">Paragraph</p>

Angular transforms the * into a <ng-template> that hosts the directive and surrounds the element and its descendants.

You can only apply one structural directive per element when using the shorthand syntax (*).

If multiple directives need to be applied, apply them in a <ng-container>.

Built-in Structural Directives

Conditionally creates or disposes of subviews from the template. (Frees up memory and resources)

By default, ngIf prevents display of an element bound to a null value.

<div *ngIf="isActive">Div</div>

To use an else block, must use a <ng-template> block with the help of a LocalReference.

<div *ngIf="isActive; else elseBlock">Div</div>
<ng-template #elseBlock>Div otherwise</ng-template>

Or with a more descriptive way.

<ng-template [ngIf]="isActive" [ngIfElse]="elseBlock">
    <div>Div</div>
</ng-template>

<ng-template #elseBlock>
    <div>Div otherwise</div>
</ng-temaplate>

NgFor

Repeat a node for each item in a list.

@Component({
    template: `
        <div *ngFor="let item of items">
            <span>{{ item.value }}</span>
        </div>
    `,
})
export class Component {
    protected items = [{ value: "Value1" }, { value: "Value2" }];
}

You may pass the item value to a sub component like.

<app-sub-component *ngFor="let item of items" [itemData]="item" />

You can get the list index with let i=index like.

<div *ngFor="let item of items; let i=index">
    <span [number]="i">{{ item.value }}</span>
</div>

You can track items with trackBy.

Angular can change and re-render only those items that have changed, rather than reloading the entire list of items.

The item list must have some sort of unique id field.

@Component({
    template: `
        <div *ngFor="let item of items; trackBy: item.id">
            <span>{{ item.value }}</span>
        </div>
    `,
})
export class Component {
    protected items = [
        { id: 1, value: "Value1" },
        { id: 2, value: "Value2" },
    ];
}

NgSwitch

To display one element among several possible elements, based on a switch condition.

@Component({
    template: `
        <ng-template [ngFor]="let item of items; trackBy: item.id">
            <div [ngSwitch]="item.value">
                <app-sub-component *ngSwitchCase="'Value1'" [itemData]="item" />
                <app-sub-component *ngSwitchCase="'Value2'" [itemData]="item" />
                <span *ngSwitchDefault >Unknown</span>
            </div
        </ng-template>
    `,
})
export class Component {
    protected items = [
        { id: 1, value: "Value1" },
        { id: 2, value: "Value2" },
    ];
}

@Directive({
    selector: "[select]",
})
export class SelectDirective {
    private templateRef = inject(TemplateRef);
    private viewContainerRef = inject(ViewContainerRef);
    selectFrom = input.required<DataSource>();
    
    async ngOnInit() {
        const data = await this.selectFrom.load();
        this.viewContainerRef.createEmbeddedView(this.templateRef, {
            /*
                Create the embedded view with a context object that contains
                the data via the key `$implicit`.
            */
            $implicit: data,
        });
    }
}
<ng-template selector let-item [selectFrom]="items">
    <p>The data is: {{ item.value }}</p>
</ng-template>

Adding Directives to a Component with hostDirectives

Only usable in standalone components.

You can assign directives to a component through the hostDirectives property inside the component's decorator.

@Component({
    hostDirectives: [MenuBehavior],
})

Angular applies host directives statically at compile time.

You cannot dynamically add directives at runtime.

Angular ignores the selector of directives applied in the hostDirectives property.

By default, host directive inputs and outputs are not exposed as part of the component's public API.

Execution order

Host directives always execute their constructor, lifecycle hooks, and binding before the component or directive on which they are applied.

This means that components with hostDirectives can override any host binding specified by a host directive.

Including inputs and outputs

By explicitly specifying the inputs and outputs, consumers of the component with hostDirective can bind them in a template.

@Component({
    hostDirectives: [{
        directive: MenuBehavior,
        inputs: ['menuId'],
        outputs: ['menuClosed']
    }],
})
export class AdminMenu { ... }
<admin-menu menuId="top-menu" (menuClosed)="logMenuClosed()">

Alias the inputs and outputs

You can also alias them to customize the API of your component.

@Component({
    hostDirectives: [{
        directive: MenuBehavior,
        inputs: ['menuId: id'],
        outputs: ['menuClosed: closed']
    }],
})
export class AdminMenu { ... }
<admin-menu id="top-menu" (closed)="logMenuClosed()">

Adding Directives to other Directives with hostDirectives

You can also add hostDirectives to other directives, in addition to components.

This enables the transitive aggregation of multiple behaviors (chainned directives).

@Directive({ ... })
export class Menu { ... }

@Directive({ ... })
export class Tooltip { ... }

// MenuWithTooltip can compose behaviors from multiple other directives
@Directive({
    hostDirectives: [Tooltip, Menu],
})
export class MenuWithTooltip { ... }

// CustomWidget can apply the already-composed behaviors from MenuWithTooltip
@Directive({
    hostDirectives: [MenuWithTooltip],
})
export class SpecializedMenuWithTooltip { }

Preffer to use .

Preffer to use .

More examples in .

Create the new directive with the .

But prefer to use .

Create the new directive with the .

When you write your own structural directives, use the .

Generate Directive (CLI)
Building an Attribute Directive
NgIf
Building a Structural Directive
following syntax
CLI command
CLI command
Class Binding [class.]
Style Binding [style.]
Binding to the host element
AngularAngular
guide/directives
Logo
Examples