Angular Directives: A Comprehensive Guide from Fundamentals to Advanced

Angular Directives: A Comprehensive Guide from Fundamentals to Advanced

·

5 min read

In Angular, directives are used to add behavior to DOM elements, either by modifying the DOM directly or by adding functionality to an element in the template. Directives are key to creating dynamic, interactive web applications. Understanding directives is essential for Angular developers, as they help enhance your UI and improve code maintainability.

What Are Angular Directives?

Directives are classes in Angular that allow you to extend HTML functionality. They can:

  1. Modify the DOM – Change the structure, style, or behavior of the element.

  2. Add behavior to DOM elements – Like handling events, controlling data, and more.

Angular provides three types of directives:

  1. Structural Directives: Change the layout of the DOM by adding or removing elements.

  2. Attribute Directives: Change the appearance or behavior of an element.

  3. Component Directives: Technically, components are also a form of directive (they use templates, but are more complex, containing both a view and logic).

Types of Directives in Angular

  1. Structural Directives: These directives alter the structure of the DOM by adding, removing, or manipulating elements.

    • Examples: *ngIf, *ngFor, ngSwitch, etc.
  2. Attribute Directives: These directives modify the appearance or behavior of an existing DOM element.

    • Examples: ngClass, ngStyle, ngModel, etc.
  3. Component Directives: These are directives with templates. Technically, every component is a directive with a template.

    • Example: app-header, app-footer (custom components).

1. Structural Directives

Structural directives are responsible for altering the structure of the DOM. They work by adding or removing elements based on conditions or loops.

Example: *ngIf

*ngIf is used to conditionally include or remove an element from the DOM.

Example Usage:
htmlCopy code<div *ngIf="isVisible">
  <h2>Welcome to Angular!</h2>
</div>
Component Class (TypeScript):
typescriptCopy codeimport { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  isVisible = true;  // Control the visibility of the element
}

In this example, the <h2> element is only displayed if isVisible is true. If it is false, the element is removed from the DOM.

Example: *ngFor

*ngFor is used to loop through a list and repeat the same DOM structure for each item.

Example Usage:
htmlCopy code<ul>
  <li *ngFor="let item of items">{{ item }}</li>
</ul>
Component Class (TypeScript):
typescriptCopy codeimport { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  items = ['Item 1', 'Item 2', 'Item 3'];
}

In this case, Angular will generate an <li> element for each item in the items array.


2. Attribute Directives

Attribute directives change the appearance or behavior of an existing DOM element. They do not change the structure of the DOM but modify the element to which they are applied.

Example: ngClass

The ngClass directive is used to add or remove CSS classes based on conditions.

Example Usage:
htmlCopy code<div [ngClass]="{ 'active': isActive, 'inactive': !isActive }">
  <h2>Directive Example</h2>
</div>
Component Class (TypeScript):
typescriptCopy codeimport { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  isActive = true;
}

Here, the class active will be applied to the <div> if isActive is true, and inactive will be applied if it is false.

Example: ngStyle

The ngStyle directive allows you to dynamically set inline styles.

Example Usage:
htmlCopy code<div [ngStyle]="{ 'color': isActive ? 'green' : 'red' }">
  <h2>Style Directive Example</h2>
</div>
Component Class (TypeScript):
typescriptCopy codeimport { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  isActive = true;  // If true, the color will be green, otherwise red
}

In this case, the color of the text will be green if isActive is true, and red if it is false.


3. Custom Directives

You can also create your own custom directives to modify the behavior of DOM elements.

Example: Custom Attribute Directive

Let’s say we want to create a custom directive that changes the background color of an element when the user hovers over it.

Step 1: Create the Directive
typescriptCopy codeimport { Directive, ElementRef, HostListener } from '@angular/core';

@Directive({
  selector: '[appHoverColor]'  // Custom selector to apply the directive
})
export class HoverColorDirective {

  constructor(private el: ElementRef) { }

  @HostListener('mouseenter') onMouseEnter() {
    this.changeColor('yellow');  // Change color on hover
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.changeColor('white');   // Revert color when hover ends
  }

  private changeColor(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}
Step 2: Use the Custom Directive in a Template
htmlCopy code<div appHoverColor>
  Hover over this text to change its background color!
</div>

Here, the appHoverColor directive is applied to the <div>, changing the background color when the user hovers over it.

Explanation:

  • ElementRef gives direct access to the DOM element that the directive is attached to.

  • HostListener listens for events like mouse enter or mouse leave and applies the desired functionality.

  • @Directive defines a custom attribute directive, which modifies the element’s behavior.


Advanced Concepts in Angular Directives

1. Structural Directives with Local Variables

In addition to adding or removing elements, structural directives like *ngIf and *ngFor can create local variables that provide additional context.

For example, *ngFor creates a local variable for each iteration, such as index or odd/even.

htmlCopy code<ul>
  <li *ngFor="let item of items; let i = index">
    {{ i + 1 }}. {{ item }}
  </li>
</ul>

Here, i will give the index of each item.

2. Dynamic Directive Creation

You can also dynamically create directives at runtime using the ComponentFactoryResolver and ViewContainerRef in Angular. This is an advanced use case but enables the loading of components or directives dynamically based on user interaction or other events.

3. Directive Lifecycle Hooks

Angular also provides lifecycle hooks for directives, such as:

  • ngOnInit(): Called when the directive is initialized.

  • ngOnDestroy(): Called when the directive is destroyed.

For instance, you could handle cleanup in ngOnDestroy when dealing with custom event listeners in directives.

typescriptCopy codeimport { Directive, OnDestroy } from '@angular/core';

@Directive({
  selector: '[appCustomDirective]'
})
export class CustomDirective implements OnDestroy {
  ngOnDestroy() {
    console.log('Directive destroyed');
  }
}

Conclusion:

  1. Directives are fundamental to building interactive UIs in Angular. They allow you to manipulate the DOM, add behaviors, and enhance user interaction.

  2. There are three types of directives: Structural, Attribute, and Component Directives.

  3. Custom directives provide a powerful way to extend Angular’s capabilities.

  4. Advanced topics such as directive lifecycle hooks and dynamic directive creation allow you to build highly dynamic and efficient Angular applications.