Learn Angular 8 Step By Step in 10 Days – Directives (Day 4)

Welcome back to the Learn Angular 8 in 10 Days article series - Part 4. In the previous article, we discussed the different concepts of Data Binding techniques. Now, in this article, we will discuss the Concept of Directives. If you want to read the previous articles of this series, then follow the links.

So, in this article, we will discuss the concept of Directive in Angular 8. The directive is another main building block of the Angular framework. Using directives, we can create different reusable UI controls of the web application in which we can define design as well as business logic, and those controls can be used in different components of the applications.

What is the Directive?

A directive modifies the DOM by changing the appearance, behavior, or layout of DOM elements. Directives just like Component are one of the core building blocks in the Angular framework to build applications. In fact, Angular 8 components are, in large part, directives with templates. In Angular 8 components have assumed a lot of the roles directives used to. In Angular 8, the major issues related to template injection and dependency injection are solved with the help of components, and issues related to providing the modification for the generic behavior of the application are done with the help of directives.

So, if we consider the high-level definition of directives, then Directives act as an HTML marker on any DOM element (like as an attribute or element name or comment or CSS-based style class) which instructs Angular’s HTML compiler to attach a specified behavior on that particular DOM element or to transform that DOM element.

Basic Concept of Directives

In Angular Framework, one of the most important elements is Directives. If we analyze the directive in brief, then we will discover that the main building block of the Angular 8 framework which is known as a Component is basically a directive. So, in a simple word, each and every Angular component is just a directive with a custom HTML template. So, in real words when defining a component as the main building block of an Angular application, actually we want to say that directives are the main building blocks of Angular applications.

In general, a directive is a TypeScript-based function that executes whenever the Angular compiler identifies it within the DOM element. Directives are used to provide or generate new HTML-based syntax which will extend the power of the UI in an Angular Application. Each directive must have a selector name just like the same as the component – either that name can be from Angular predefined patterns like ng-if or a custom developer-defined name which can be any name but needs to indicate the main purpose of the directive. Also, every directive can act as an element an attribute a class, or a comment in the HTML section.

Why Directives Required?

In Angular Framework, Directives always ensure the high level of reusability of the UI controls throughout the application. With the help of Directives, we can develop UIs with many movable parts, and at the same time, we can streamline the development flow for the engineers. The main reasons for using directives in any Angular applications are,

  1. Reusability: In an Angular application, the directive is a self-sufficient part of the UI. As a developer, we can reuse the directive across the different parts of the application. This is very useful in any large-scale applications where multiple systems need the same functional elements like search box, date control, etc.
  2. Readability: The directive provides much more readability for the developers to understand the production functionality and data flow.
  3. Maintainability: One of the main uses of directives in any application is maintainability. We can easily decouple the directive from the application and replace the old one with a new directive. 

Component vs Directives

The comparison between Component and directives is as below.

Component Directives
A component is defined with the @Component decorator A Directive is defined with the @Directives decorator
A component is a directive that uses a shadow DOM to create encapsulated visual behavior called a component. Components are typically used to create UI widgets. The directive is mainly used to provide new behavior within the existing DOM elements.
With the help of the component, we can break down the application into multiple small parts. With the help of the directive, we can design any type of reusable component.
In the browser DOM, only one component can be activated as a parent component. Other components will act like a child component in that case. Within a single DOM element, any no of directives can be used.
@View decorator or templateUrl template is mandatory in the component. Directives don’t use View.


@Directive Metadata

@Directive decorator is used to define any class as an Angular Directive. We can always define any directive to specify the custom behavior of the elements within the DOM. @Directive() metadata contains the below-mentioned options.

  1. selector: The selector property is used to identify the directive within the HTML template. Also, with the help of this property, we can initialize the directive from the DOM elements
  2. inputs: It is used to provide the set of data-bound input properties of the directives.
  3. outputs: It is used to enumerate any event properties from the directives.
  4. providers: It is used to inject any provider type like service or components within the directives.
  5. exportAs: It is used to define the name of the directives which can be used to assign a directive as a variable.

Types of Directives

There are three main types of directives in Angular 8

  • Component: Directives with templates.
  • Attribute Directives: Directives that change the behavior of a component or element but don’t affect the template.
  • Structural Directives: Directives that change the behavior of a component or element by affecting the template or the DOM decoration of the UI.
    Directives in angular

What is an Attribute Directive?

Attribute directives are mainly used for changing the appearance or behavior of a component or a native DOM element. Attribute directives actually modify the appearance or behavior of an element. These directives actually act as a simple HTML attribute for any HTML tag. There are some inbuild attribute directives available in the framework like ngModel. But, we can also create any type of custom attribute-based directive as per our requirement. In that case, use the attribute directive selector name as an attribute within the HTML tag in the HTML code section.

In-Built Attribute Directives

Angular 8 provides some inbuilt Attribute directives that can be used to change the style or attributes of the HTML elements in the DOM. Those attribute directives are,

  • ngClass: ngClass directive changes the class attribute that is bound to the component or element it's attached to.
  • ngStyle: ngStyle is mainly used to modify or change the element’s style attribute. This attribute directive is quite similar to using style metadata in the component class.

What is a Structural Directive?

Another type of directive in the Angular framework is the Structural Directive. Structural directives are mainly used to change the design pattern of the UI DOM elements. In HTML, these directives can be used as a template tag. Using this type of directive, we can change the structure of any DOM elements and can redesign or redecorate those DOM elements. In Angular Framework, there are some systems that generate structural directives available like ngIf, ngFor, and ngSwitch. We can also create any custom structural directive. The most common example of any custom structural directives is components. Since we can consider every component as a structural directive if that component makes some change in the UI DOM element's style or design. All the system-generated structural directives have a template name along with some property value that needs to be provided when we define those directives in the HTML code.

In-Build Structural Directive

Angular 8 provides below mentioned built-in directives which can be used within a component to change the elements' structure or design.

  • ngIf
  • ngFor
  • ngSwitch

Custom Directive

To create attribute directives, we always need to use or inject the below objects in our custom attribute directive component class. To create an attribute directive, we need to remember the below topics.

  1. Import required modules like directives, ElementRef, and renderer from the Angular core library.
  2. Create a TypeScript class.
  3. Use the @Directive decorator in the class.
  4. Set the value of the selector property in the @directive decorator function. The directive will be used, using the selector value on the elements.
  5. In the constructor of the class, inject ElementRef and the renderer object.
  6. You need to inject ElementRef in the directive’s constructor to access the DOM element.
  7. You also need to inject the renderer in the directive’s constructor to work with the DOM’s element style.
  8. You need to call the renderer’s setElementStyle function. In this function, we need to pass the instance of the current DOM element with the help of ElementRef as a parameter and set the behavior or property of the current element.
  9. ElementRef: While creating a custom attribute directive, we inject ElementRef in the constructor to access the DOM element. ElementRef provides access to the underlying native element. With the help of ElementRef, we can obtain direct access to the DOM element using its nativeElement property. In that case, ElementRef is behaving just like a service. That’s all we need to set the element’s color using the browser DOM API.
  10. Renderer: While creating a custom attribute directive, we inject Renderer in the constructor to access the DOM element’s style. Actually, we call the renderer’s setElementStyle function. In this function, we pass the current DOM element with the help of the ElementRef object and set the required attribute of the current element.
  11. HostListener: Sometimes we may need to access the input property within the attribute directive so that, as per the given attribute directive, we can apply a related attribute within the DOM Element. To trap user actions, we can call different methods to handle user actions. We need to use this method to perform any user action. For that purpose, we need to decorate the method with the @HostListener method.

Demo 1. Attribute Directive

Now in this demo, we will demonstrate how to use inbuilt attribute directives in Angular Framework.

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls : ['./custom.css']
})
export class AppComponent {
  
  showColor: boolean = false;
  
  constructor() { }
  
  public changeColor(): void {
    this.showColor = !this.showColor;
  }
}

app.component.html

<div>
  <h3>This is a Attribute Directives</h3>
  <span [class.red]="true">Attribute Change</span><br />
  <span [ngClass]="{'blue':true}">Attribute Change by Using NgClass</span><br />
  <span [ngStyle]="{'font-size':'14px','color':'green'}">Attribute Change by Using NgStyle</span>
  <br /><br />
  <span [class.cyan]="showColor">Attribute Change</span><br />
  <span [ngClass]="{'brown':showColor}">Attribute Change by Using NgClass</span><br />
  <input type="button" value="Change Color" (click)="changeColor()" />
  <br /><br />
  <span [class.cyan]="showColor">Attribute Change</span><br />
  <span [ngClass]="{'cyan':showColor, 'red' : !showColor}">Attribute Change by Using NgClass</span><br />
  <br />
</div>

custom.css

.red { color: red; }
.blue { color: blue; }
.cyan { color: cyan; }
.brown { color: brown; }

Now check the output in the browser.

Attribute

Demo 2. ngIf

Now in this demo, we will explain how to use ngIf in our angular application.

app.component.ts

import { Component } from '@angular/core';

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

  showInfo: boolean = false;
  caption: string = 'Show Text';

  constructor() { }

  public changeData(): void {
    this.showInfo = !this.showInfo;
    if (this.showInfo) {
      this.caption = 'Hide Text';
    } else {
      this.caption = 'Show Text';
    }
  }
}

app.component.html

<div>
  <input type="button" value="{{caption}}" (click)="changeData()"/>
  <br />
  <h2 *ngIf="showInfo"><span>Demonstrate of Structural Directives - *ngIf</span></h2>
</div>

Now check the output in the browser.

Angular

Demo 3. ngFor

Now in this demo, we will explain how to use ngFor in our angular application.

app.component.ts

import { Component } from '@angular/core';

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

  productList: Array<string> = ['IPhone', 'Galaxy 9.0', 'Blackberry 10Z'];

  constructor() { }
}

app.component.html

<div>
  <h2>Demonstrate ngFor</h2>
  <ul>
    <li *ngFor="let item of productList">
      {{ item }}
    </li>
  </ul>
</div>

Now check the output in the browser.

Browser

Demo 4. ngSwitch

Now in this demo, we will explain how to use ngSwitch in our angular application.

app.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./custom.css']
})
export class AppComponent implements OnInit {

  studentList: Array<any> = new Array<any>();

  constructor() { }

  ngOnInit() {
    this.studentList = [
      { SrlNo: 1, Name: 'Rajib Basak', Course: 'Bsc(Hons)', Grade: 'A' },
      { SrlNo: 2, Name: 'Rajib Basak1', Course: 'BA', Grade: 'B' },
      { SrlNo: 3, Name: 'Rajib Basak2', Course: 'BCom', Grade: 'A' },
      { SrlNo: 4, Name: 'Rajib Basak3', Course: 'Bsc-Hons', Grade: 'C' },
      { SrlNo: 5, Name: 'Rajib Basak4', Course: 'MBA', Grade: 'B' },
      { SrlNo: 6, Name: 'Rajib Basak5', Course: 'MSc', Grade: 'B' },
      { SrlNo: 7, Name: 'Rajib Basak6', Course: 'MBA', Grade: 'A' },
      { SrlNo: 8, Name: 'Rajib Basak7', Course: 'MSc.', Grade: 'C' },
      { SrlNo: 9, Name: 'Rajib Basak8', Course: 'MA', Grade: 'D' },
      { SrlNo: 10, Name: 'Rajib Basak9', Course: 'B.Tech', Grade: 'A' }
    ];
  }
}

app.component.html

<div>
  <h2>Demonstrate ngSwitch</h2>
  <table style="width:100%;border:solid;border-color:blue;border-width:thin;">
    <thead>
      <tr>
        <td>Srl No</td>
        <td>Student Name</td>
        <td>Course</td>
        <td>Grade</td>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let student of studentList;" [ngSwitch]="student.Grade">
        <td>
          <span *ngSwitchCase="'A'" [ngStyle]="{'font-size':'18px','color':'red'}">{{student.SrlNo}}</span>
          <span *ngSwitchCase="'B'" [ngStyle]="{'font-size':'16px','color':'blue'}">{{student.SrlNo}}</span>
          <span *ngSwitchCase="'C'" [ngStyle]="{'font-size':'14px','color':'green'}">{{student.SrlNo}}</span>
          <span *ngSwitchDefault [ngStyle]="{'font-size':'12px','color':'black'}">{{student.SrlNo}}</span>
        </td>
        <td>
          <span *ngSwitchCase="'A'" [ngStyle]="{'font-size':'18px','color':'red'}">{{student.Name}}</span>
          <span *ngSwitchCase="'B'" [ngStyle]="{'font-size':'16px','color':'blue'}">{{student.Name}}</span>
          <span *ngSwitchCase="'C'" [ngStyle]="{'font-size':'14px','color':'green'}">{{student.Name}}</span>
          <span *ngSwitchDefault [ngStyle]="{'font-size':'12px','color':'black'}">{{student.Name}}</span>
        </td>
        <td>
          <span *ngSwitchCase="'A'" [ngStyle]="{'font-size':'18px','color':'red'}">{{student.Course}}</span>
          <span *ngSwitchCase="'B'" [ngStyle]="{'font-size':'16px','color':'blue'}">{{student.Course}}</span>
          <span *ngSwitchCase="'C'" [ngStyle]="{'font-size':'14px','color':'green'}">{{student.Course}}</span>
          <span *ngSwitchDefault [ngStyle]="{'font-size':'12px','color':'black'}">{{student.Course}}</span>
        </td>
        <td>
          <span *ngSwitchCase="'A'" [ngStyle]="{'font-size':'18px','color':'red'}">{{student.Grade}}</span>
          <span *ngSwitchCase="'B'" [ngStyle]="{'font-size':'16px','color':'blue'}">{{student.Grade}}</span>
          <span *ngSwitchCase="'C'" [ngStyle]="{'font-size':'14px','color':'green'}">{{student.Grade}}</span>
          <span *ngSwitchDefault [ngStyle]="{'font-size':'12px','color':'black'}">{{student.Grade}}</span>
        </td>
      </tr>
    </tbody>
  </table>
</div>

Now check the output in the browser.

Ngswitch

Demo 5. Custom Directive Color Change

Now, in this demo, we will create custom attribute-based directives that will change the color of the selected text on mouseover. For that, we need to first create the directive below.

app.directive.ts

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

@Directive({
    selector: '[colorchange]'
})
export class ColorChangeDirective {
    private _defaultColor = 'red';
    @Input('colorchange') highlightColor: string;

    constructor(private el: ElementRef, private render: Renderer) { }

    @HostListener('mouseenter') onMouseEnter() {
        console.log(this.highlightColor);
        this.changeColor(this.highlightColor || this._defaultColor);
    }

    @HostListener('mouseleave') onMouseLeave() {
        console.log(this.highlightColor);
        this.changeColor(null);
    }

    private changeColor(color: string) {
        this.render.setElementStyle(this.el.nativeElement, 'color', color);
    }
}

Now, we need to use this custom directive in our app-root component as below.

app.component.ts

import { Component } from '@angular/core';

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

  public message: string = 'Sample Demostration of Attribute Directives using Custom Directives';
  public color: string = 'blue';

}

app.component.html

<div>
    <input type="radio" name="colors" (click)="color='blue'">blue
    <input type="radio" name="colors" (click)="color='orange'">orange
    <input type="radio" name="colors" (click)="color='green'">green
</div>
<h1 [colorchange]="color">{{message}}</h1>

Now, include the above-created custom directive in our AppModule as below.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { ColorChangeDirective } from './app.directive';

@NgModule({
  declarations: [
    AppComponent,
    ColorChangeDirective
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Now, run the output in the browser as below.

Output

Conclusion

In this article, we discussed another main building block in Angular 8 e.i. Directives. Also, we discussed the different types of directives like attribute directives and structural directives. Now, in the next article, we will discuss another important part of Angular i.e. Pipe. I hope this article will help you. Any feedback or query related to this article is most welcome.

Next Article, Learn Angular 8 Step By Step in 10 Days – Pipes (Day 5)