Mastering Angular Directives – ngIf, ngFor, ngClass & Custom Directive Tutorial

Mastering Angular Directives – ngIf, ngFor, ngClass & Custom Directive Tutorial

AI Reading

Quick summary of this article

Angular directives are classes that attach behavior to DOM elements, and they come in three types: component, structural, and attribute directives. The article explains built-in directives like *ngIf, *ngFor, and [ngClass], then shows how to build a custom attribute directive that changes an element's background color on mouse enter and leave.

  • Structural directives change the DOM layout: *ngIf conditionally shows content (including if/else logic with ng-template), and *ngFor loops over a collection.
  • Attribute directives change an element's appearance or behavior: [ngClass] applies CSS classes dynamically based on conditions, such as pass or fail.
  • Custom directives are created with the Angular CLI command ng generate directive highlight, then given logic using ElementRef, Renderer2, and HostListener.
  • The example HighlightDirective sets a yellow background on mouseenter and removes it on mouseleave, and is used in a template with <p appHighlight>.
  • Best practices include using *ngIf and *ngFor for conditional rendering, [ngClass] or [ngStyle] for dynamic styles, and Renderer2 for safe DOM manipulation.

Chapter 5: Directives in Angular

Angular directives are powerful tools that let you manipulate the DOM and extend HTML behavior. This chapter focuses on both built-in directives and creating your own custom ones for dynamic and reusable UI components.

What Are Directives?

Directives are classes in Angular that allow you to attach behavior to elements in the DOM. There are three types:

  • Component Directives – With templates
  • Structural Directives – Change the DOM layout (e.g., *ngIf, *ngFor)
  • Attribute Directives – Change the appearance or behavior of elements (e.g., [ngClass])

Complete Code: marks.component.ts


import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HighlightDirective } from './highlight.directive';

@Component({
  selector: 'app-marks',
  standalone: true,
  imports: [CommonModule, HighlightDirective],
  templateUrl: './marks.component.html',
  styleUrl: './marks.component.css'
})
export class MarksComponent {
  mathematics = 85;
  science = 78;
  english = 92;
  hindi = 88;
  history = 74;
  computerScience = 95;

  users = [
    { name: 'John Doe' },
    { name: 'Jane Smith' },
    { name: 'Mike Johnson' }
  ];

  get total(): number {
    return this.mathematics + this.science + this.english + 
           this.hindi + this.history + this.computerScience;
  }

  get average(): number {
    return this.total / 6;
  }
}

Complete Code: highlight.directive.ts


import { Directive, ElementRef, Renderer2, HostListener } from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  standalone: true
})
export class HighlightDirective {
  constructor(private el: ElementRef, private renderer: Renderer2) {}

  @HostListener('mouseenter') onMouseEnter() {
    this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', 'yellow');
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.renderer.removeStyle(this.el.nativeElement, 'backgroundColor');
  }
}

marks.component.html


<h2>Student Marks Summary</h2>

<p>Total Marks: {{ total }}</p>
<p>Average Marks: {{ average }}</p>

<!-- Using *ngIf to conditionally show messages -->
<p *ngIf="average >= 90">Excellent performance! 🎉</p>
<p *ngIf="average < 90">Keep working hard! 💪</p>

<h2>Student Marks Summary</h2>

<p>Total Marks: {{ total }}</p>
<p>Average Marks: {{ average }}</p>

<!-- if / else if / else logic using ng-template -->
<p *ngIf="average >= 90; else goodMarks">Excellent performance! 🎉</p>

<ng-template #goodMarks>
  <p *ngIf="average >= 75; else improvement">Good performance! 👍</p>
</ng-template>

<ng-template #improvement>
  <p>Needs improvement! 📚</p>
</ng-template>

*ngFor

Used to loop over a collection:


<ul>
  <li *ngFor="let user of users">{{ user.name }}</li>
</ul>

Built-in Attribute Directive: [ngClass]

[ngClass] lets you dynamically apply CSS classes based on conditions:


<h2>Student Marks Summary</h2>

<p>Total Marks: {{ total }}</p>
<p>Average Marks: {{ average }}</p>

<!-- Apply pass/fail class using [ngClass] -->
<div [ngClass]="{ 'pass': average >= 40, 'fail': average < 40 }">
  Result Status
</div>

marks.component.css


.pass {
  color: green;
  font-weight: bold;
  background-color: #d4edda;
  padding: 10px;
  border-radius: 5px;
}

.fail {
  color: red;
  font-weight: bold;
  background-color: #f8d7da;
  padding: 10px;
  border-radius: 5px;
}

table {
  width: 100%;
  border-collapse: collapse;
}

th, td {
  padding: 12px;
  text-align: left;
  border: 1px solid #ddd;
}

tr:hover {
  background-color: #f5f5f5;
}

Creating Custom Attribute Directive

Step 1: Create Directive


ng generate directive highlight

Step 2: Add Logic


import { Directive, ElementRef, Renderer2, HostListener } from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  standalone: true
})
export class HighlightDirective {
  constructor(private el: ElementRef, private renderer: Renderer2) {}

  @HostListener('mouseenter') onMouseEnter() {
    this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', 'yellow');
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.renderer.removeStyle(this.el.nativeElement, 'backgroundColor');
  }
}

This directive changes background color on mouse events. Use it like:


<p appHighlight>Hover to highlight me!</p>

Complete Final Code: All Files Together

✅ marks.component.ts (Complete)


import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HighlightDirective } from './highlight.directive';

@Component({
  selector: 'app-marks',
  standalone: true,
  imports: [CommonModule, HighlightDirective],
  templateUrl: './marks.component.html',
  styleUrl: './marks.component.css'
})
export class MarksComponent {
  mathematics = 85;
  science = 78;
  english = 92;
  hindi = 88;
  history = 74;
  computerScience = 95;

  users = [
    { name: 'John Doe' },
    { name: 'Jane Smith' },
    { name: 'Mike Johnson' }
  ];

  get total(): number {
    return this.mathematics + this.science + this.english + 
           this.hindi + this.history + this.computerScience;
  }

  get average(): number {
    return this.total / 6;
  }
}

✅ highlight.directive.ts (Complete)


import { Directive, ElementRef, Renderer2, HostListener } from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  standalone: true
})
export class HighlightDirective {
  constructor(private el: ElementRef, private renderer: Renderer2) {}

  @HostListener('mouseenter') onMouseEnter() {
    this.renderer.setStyle(this.el.nativeElement, 'backgroundColor', 'lightyellow');
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.renderer.removeStyle(this.el.nativeElement, 'backgroundColor');
  }
}

✅ marks.component.html (Complete)


<h2>Student Marks Table</h2>

<table border="1">
  <tr>
    <th>Subject</th>
    <th>Marks</th>
  </tr>
  <tr appHighlight>
    <td>Mathematics</td>
    <td>{{ mathematics }}</td>
  </tr>
  <tr appHighlight>
    <td>Science</td>
    <td>{{ science }}</td>
  </tr>
  <tr appHighlight>
    <td>English</td>
    <td>{{ english }}</td>
  </tr>
  <tr appHighlight>
    <td>Hindi</td>
    <td>{{ hindi }}</td>
  </tr>
  <tr appHighlight>
    <td>History</td>
    <td>{{ history }}</td>
  </tr>
  <tr appHighlight>
    <td>Computer Science</td>
    <td>{{ computerScience }}</td>
  </tr>
</table>

<!-- Using *ngIf examples -->
<p *ngIf="average >= 90">Excellent performance! 🎉</p>
<p *ngIf="average < 90">Keep working hard! 💪</p>

<!-- ngClass example -->
<div [ngClass]="{ 'pass': average >= 40, 'fail': average < 40 }">
  Result Status: {{ average >= 40 ? 'PASS' : 'FAIL' }}
</div>

Best Practices

  • Use *ngIf and *ngFor to conditionally render DOM elements.
  • Use [ngClass] or [ngStyle] for dynamic styles.
  • Create custom directives to keep templates clean and behavior reusable.
  • Prefer Renderer2 for DOM manipulation to ensure compatibility.

Conclusion

Directives are essential to building dynamic UIs in Angular. Whether you use built-in options or create custom ones, mastering directives will elevate your frontend development skills and keep your code modular and expressive.

Next Steps

In Chapter 6, we’ll dive into Angular Pipes — a powerful way to transform and format data directly within templates.

Leave a Reply

Your email address will not be published. Required fields are marked *