Directives in Angular: A Beginner’s Guide

dalanda drissi
7 min readSep 6, 2023

--

Introduction

Imagine you have the power to create your own custom HTML elements with unique behaviors, encapsulated logic, and reusable structures in your web application. This power is exactly what Angular’s component directives offer! In this article, we embark on a journey to demystify component directives in Angular, uncovering their potential and showing you how to wield them to build dynamic and interactive web applications.

What Are Directives? 🧐

Think of directives in Angular as the cool backstage crew that tells the HTML how to perform its best on stage. They’re like secret agents with superpowers that transform your static HTML into a dynamic, interactive experience.

Types of Directives

Angular brings three types of directives to the party:

1.Component Directives :

These are like the main actors in your Angular play. They combine both the user interface (HTML template) and the logic (TypeScript code) into one reusable package. Components are your building blocks for creating custom elements with unique behaviors.

Example:

Imagine you’re building a weather app, and you create a component directive called <app-weather-card>. This directive encapsulates the display and logic for showing weather information.

Step 1: Component Creation

First, we create a new Angular component using the Angular CLI. We’ll call it weather-card.

ng generate component weather-card

Step 2: Component Template (HTML)

Inside the weather-card component's folder, we find a template file named weather-card.component.html. This is where we define the HTML structure of our Weather Card.

<!-- weather-card.component.html -->
<div class="weather-card">
<h2>{{ city }}</h2>
<p>Temperature: {{ temperature }}°C</p>
<p>Conditions: {{ conditions }}</p>
</div>

In this template, we’ve defined the structure of a Weather Card, which includes the city name, temperature, and weather conditions.

Step 3: Component Class (TypeScript)

Next, we open the weather-card.component.ts file, which contains the TypeScript code for our component.

// weather-card.component.ts
import { Component, Input } from '@angular/core';

@Component({
selector: 'app-weather-card',
templateUrl: './weather-card.component.html',
styleUrls: ['./weather-card.component.css']
})
export class WeatherCardComponent {
@Input() city: string;
@Input() temperature: number;
@Input() conditions: string;
}

In this component class, we:

  • Import the necessary modules from @angular/core.
  • Use the @Component decorator to specify the selector, template URL, and style URLs.
  • Define three input properties (city, temperature, and conditions) using the @Input() decorator. These properties will receive data from the parent component.

Step 4: Component Styling (CSS)

Optionally, we can style our Weather Card component by adding styles in the weather-card.component.css file.

/* weather-card.component.css */
.weather-card {
border: 1px solid #ccc;
padding: 10px;
margin: 10px;
border-radius: 5px;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
}

.weather-card h2 {
font-size: 20px;
margin-bottom: 5px;
}

.weather-card p {
margin: 0;
}

This CSS file defines styles for our Weather Card component to make it visually appealing.

Step 5: Using the Weather Card Component

Now that we’ve created our Weather Card component, we can use it in our application’s templates. Let’s say we have a parent component that wants to display weather information for multiple cities:

<div>
<app-weather-card [city]="'New York'" [temperature]="25" [conditions]="'Sunny'"></app-weather-card>
<app-weather-card [city]="'London'" [temperature]="18" [conditions]="'Partly Cloudy'"></app-weather-card>
<app-weather-card [city]="'Tokyo'" [temperature]="30" [conditions]="'Rainy'"></app-weather-card>
</div>

In the above code, we’re using the app-weather-card component and passing data to it using the [city], [temperature], and [conditions] input properties. Each instance of the Weather Card component displays weather information for a different city.

2.Attribute Directives

Attribute directives in Angular are used to change the appearance or behavior of an existing DOM element by manipulating its attributes.

Examples:

  • ngClass : The ngClass directive allows you to dynamically apply CSS classes to an element based on conditions or expressions.
<div [ngClass]="{'active': isActive, 'disabled': isDisabled}">
Dynamic classes
</div>
  • ngStyle : The ngStyle directive lets you apply inline styles to an element based on conditions or expressions.
<div [ngStyle]="{'color': isActive ? 'green': 'red', 'font-size.px': fontSize}">
Dynamic styles
</div>
  • ngModel : The ngModel directive is used for two-way data binding with form elements like input, select, and textarea.
<input [(ngModel)]="username" />
  • ngIf : While ngIf is primarily a structural directive, it's also an attribute directive when used as an attribute to conditionally render elements.
<div *ngIf="showElement">This element is conditionally displayed.</div>
  • ngFor : Similar to ngIf, the ngFor directive is a structural directive used for iteration, but it's also an attribute directive when used as an attribute to iterate over elements.
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
  • ngDisabled : The ngDisabled directive is used to disable or enable form elements based on a condition.
<button [disabled]="isDisabled">Click me</button>
  • ngReadOnly : The ngReadOnly directive is used to set the read-only property of form elements.
<input [readOnly]="isReadOnly" />
  • ngSwitch and ngSwitchCase : The ngSwitch directive is used to conditionally render content based on a given expression, and ngSwitchCase is used to specify the cases.
<div [ngSwitch]="value">
<p *ngSwitchCase="'A'">Value is A</p>
<p *ngSwitchCase="'B'">Value is B</p>
<p *ngSwitchDefault>Value is neither A nor B</p>
</div>
  • ng-container : While not a traditional structural directive, <ng-container> is often used to group elements when you need to apply structural directives to multiple elements without introducing an additional wrapping element in the DOM. <ng-container> is a non-rendered element. It is not added to the DOM, so it doesn't introduce any additional elements or styles.It’s useful when you want to conditionally render multiple elements without wrapping them in a parent element.
<ng-container *ngIf="condition">
<p>Conditionally displayed paragraph.</p>
<p>Another paragraph.</p>
</ng-container>
  • ngTemplateOutlet : is a powerful feature in Angular that allows you to dynamically render templates within your components. It’s often used in combination with the ng-container element to conditionally render content or apply templates in a flexible way. ngTemplateOutlet is particularly useful when you want to reuse and render templates based on certain conditions or data.

Here’s a more detailed explanation of ngTemplateOutlet:

Step 1. Creating Templates: First, you define your templates using the <ng-template> element in your component's HTML. These templates can contain any HTML and Angular code you want to render conditionally.

<ng-template #myTemplate>
<!-- Your template content here -->
</ng-template>

Step 2. Using ngTemplateOutlet: Next, you can use the ngTemplateOutlet directive to render the template defined above within your component's HTML. You specify the template reference using the ngTemplateOutlet directive and bind it to a variable in your component.

<ng-container *ngTemplateOutlet="myTemplate"></ng-container>

In this example, the content of the myTemplate template is rendered within the <ng-container>.

Step 3. Conditional Rendering : You can conditionally render templates based on your component’s logic. For example, you might use an *ngIf directive to determine when to render a specific template:

<ng-container *ngIf="condition; then myTemplate else anotherTemplate"></ng-container>
<ng-template #anotherTemplate>
<!-- Another template content here -->
</ng-template>

In this case, if the condition is true, the myTemplate is rendered; otherwise, the anotherTemplate is rendered.

Step 4. Passing Data : You can also pass data to your templates using ngTemplateOutletContext. This allows you to dynamically bind data to your templates:

<ng-container *ngTemplateOutlet="myTemplate; context: myContext"></ng-container>

In your component TypeScript code, you would define myContext as an object containing the data you want to pass to the template.

Dynamic Template Selection : You can dynamically select which template to render based on your component’s logic or data. For example, you can use a function to determine which template to render within the ngTemplateOutlet directive.

<ng-container *ngTemplateOutlet="getTemplate()"></ng-container>

In your component, getTemplate() is a method that returns the template reference based on your logic.

3.Structural Directives

These are like the architects, reshaping your DOM by adding or removing elements. Also prefixed with *ng, they are used for more complex structural changes.

Examples

  • ngForOf : The *ngForOf directive is similar to *ngFor but is used for more complex scenarios where you want to iterate over a custom iterable like a Map or Set.
<div *ngFor="let item of itemMap | keyvalue">
{{ item.key }}: {{ item.value }}
</div>
  • ng-container: While not a traditional structural directive, <ng-container> is often used to group elements when you need to apply structural directives to multiple elements without introducing an additional wrapping element in the DOM.
<ng-container *ngIf="condition">
<p>Conditionally displayed paragraph.</p>
<p>Another paragraph.</p>
</ng-container>
  • ngIf
  • ngFor

Creating Your Own Directives🧙‍♂️

Creating custom directives in Angular is like crafting your own magic spells:

Step 1 : Import the Directive Module

First, you import the Directive module from @angular/core.

Step 2 : Define the Directive

Create a TypeScript class that represents your directive. Decorate it with @Directive to specify its selector and input properties.

Example: Let’s create a directive that adds a confetti effect to an element when you click it:

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

@Directive({
selector: '[appConfettiOnClick]'
})
export class ConfettiOnClickDirective {
@Input() colors: string[] = ['red', 'blue', 'yellow'];

constructor(private el: ElementRef) {}

@HostListener('click') onClick() {
const randomColor = this.colors[Math.floor(Math.random() * this.colors.length)];
this.el.nativeElement.style.backgroundColor = randomColor;
// Add your confetti logic here! 🎉
}
}

Step 3 : Use the Directive

Now, sprinkle some directive magic in your HTML by adding it as an attribute.

Example: Let’s use our appConfettiOnClick directive on a button:

<button appConfettiOnClick [colors]="['pink', 'green', 'purple']">Click for Confetti!</button>

Conclusion

Angular directives are like the fairy dust that turns your web applications into dynamic and interactive masterpieces. They might seem daunting at first, but with a bit of practice, you’ll find them to be your best buddies in the Angular world. So, don’t hesitate — dive into the world of directives and make your web apps shine! ✨ Happy coding!

--

--

dalanda drissi

Passionate software engineer crafting web magic with JS. Let's innovate the digital realm together!