In Angular 1.x, we say that “Directives extend the HTML with new attributes” but now, in Angular 2, we can’t describe directives as we previously did. In Angular 2, the directives are more flexible and provide many features that we missed in Angular 1.x.
In Angular 2, components are just one type of directives. When we render any component in a template file, actually it is a instruction to Angular that at this place, we want to use “this” particular component and render the template section of this component here.
In the above image, we use “ngFor” directive which is an instruction to Angular to loop through each value of technology items and perform the below operation and/or task.
Types of Directives in Angular 2
In Angular 2, we have three types of directives.
- Attribute Directives
- Structural Directives
- Component Directives
Attribute Directives
Attribute directives change the behavior and appearance of an element. Example of attribute directive is “ngClass”,”ngStyle” etc.
Example
App.component.ts
- import { Component,Input,Output,EventEmitter } from '@angular/core';
-
- @Component({
- selector: '[app-root]',
- templateUrl: './app.component.html',
- styleUrls: ['./app.component.css']
- })
-
-
- export class AppComponent {
- name:String = 'This is directive example';
-
-
- ChangeValue(data:String){
- this.name=data;
- }
-
- technology=[
- {name:"Asp.NET MVC", experience:"1 Years"},
- {name:"Android", experience:"1 Years"},
- {name:"Ionic", experience:"6 Months"},
- {name:"Angular", experience:"1 Years"},
- {name:"Node.js", experience:"6 Months"}
- ];
-
-
- }
App.component.html
- <div [ngStyle]="{'width':'450px', 'margin-left':'150px','border':'4px solid #7142f4'}">
- <h3 [ngStyle]="{'color':'#42f46e','font-size':'26px'}">
- {{name}}
- </h3>
- <h3>I am working on these technologies</h3>
- <table [ngClass]="'table'">
- <tr><th>Technology</th><th>Experiences</th></tr>
- <tr *ngFor="let data of technology">
- <th>{{data.name}}</th><th>{{data.experience}}</th>
- </tr>
- </table>
- </div>
App.component.css
- .customStyle{
- color: blue;
- font-size: 24px;
- width:300px;
- height: 30px;
- margin-top: 50px
- }
-
- .table{
- font-size: 24px;
- font-family: Cambria, Cochin, Georgia, Times, Times New Roman, serif;
- color:white;
- margin-left: 100px
-
- }
-
- .table tr:nth-child(even) {
- background-color: #87b793;
- }
-
- .table tr:nth-child(odd) {
- background-color: #a187b7;
- }
Output
In app.component.html page, we use “ngStyle” attribute directive to implement the inline CSS and “ngClass” attribute directive for implementing the class style for table.
Custom Attribute Directive
Now, we will create our own custom attribute directive. To create a directive, run “ng generate directive custom” command. This command creates a directive named “custom”.
When you open “custom.directive.ts” file, you will get the following code.
In the above code, “@Directive” is metadata that defines this class as directive. Now, replace the above code with this one.
- import { Directive,ElementRef,Renderer } from '@angular/core';
-
- @Directive({
- selector: '[appCustom]'
- })
- export class CustomDirective {
-
- private element:ElementRef;
- private renderref_:Renderer;
- constructor(element:ElementRef,renderref_:Renderer) {
- this.element=element;
- this.renderref_=renderref_;
-
-
- this.renderref_.setElementStyle(this.element.nativeElement,'background-color','yellow');
- this.renderref_.setElementStyle(this.element.nativeElement,'color','blue');
- this.renderref_.setElementStyle(this.element.nativeElement,'font-size','24px');
- this.renderref_.setElementStyle(this.element.nativeElement,'margin-top','5px');
-
-
-
- }
-
- }
Let’s understand what is happening in this code. You can see that constructor of directives contains two parameters. “ElementRef” contains the reference of host element and “Renderrer” is used to render the element with styles. In the next lines, we will add the styles for “nativeElement”. Here, nativeElement denotes the element that contains this attribute.
Now, we will use this custom attribute directive in our template page.
We have added a div element and used the custom attribute directive “AppCustom” in this div element. Now, save all changes and refresh the browser.
You can see that all the styles that we implement on this custom attribute are rendered successfully.
Add Event Listener for Custom Directives
Similar to an element, we can add event listener like ‘mouseneter’, ’mouseleave’,’click’ etc. for a custom directive. Let’s add some event listeners for our custom directive. Replace the code of your “custom.directives.ts” file with the below code.
- import { Directive,ElementRef,Renderer,HostListener,HostBinding } from '@angular/core';
-
- @Directive({
- selector: '[appCustom]'
- })
- export class CustomDirective {
-
- private element:ElementRef;
- private renderref_:Renderer;
- private backgroundColor="yellow";
- private fontSize="24px";
- @HostListener('mouseenter') mouseenter(){
- this.backgroundColor="red";
- this.fontSize="30px";
- }
-
- @HostListener('mouseleave') mouseleave(){
- this.backgroundColor="yellow";
- this.fontSize="24px";
- }
-
- @HostBinding('style.backgroundColor') get ColorValue(){
- return this.backgroundColor;
- }
- @HostBinding('style.fontSize') get fontValue(){
- return this.fontSize;
- }
-
- constructor(element:ElementRef,renderref_:Renderer) {
-
- this.element=element;
- this.renderref_=renderref_;
-
-
- this.renderref_.setElementStyle(this.element.nativeElement,'background-color','yellow');
- this.renderref_.setElementStyle(this.element.nativeElement,'color','blue');
- this.renderref_.setElementStyle(this.element.nativeElement,'font-size','24px');
- this.renderref_.setElementStyle(this.element.nativeElement,'margin-top','5px');
- }
-
-
-
- }
Let’s understand the above code.
In the first line, we import the “HostListener” and “HostBinding” modules in our custom directive.
After that, using “HostBinding”, we bind two attributes of an element with the property of our directives class. The @HostBinding decorator allows us to link a directive property to an element of the host component. In the below code, we bind “backgroundColor” property with “ColorValue” element and “fontSize” property with “fontValue” element.
In the above line of code, we added two eventListener for “mouseneter” and “mouseleave” event. Whenever this event occurs, the “mouseenter” and “mouseleave” functions will be called, that are attached with these events. In these functions, we are changing values of “backgroudnColor” and “fontSize” property. As we said before, these two properties are bound with two attributes of element, so the values of these attributes will change.
When the mouse comes over, the attributes backgroundColor and fontSize will be changed.
When mouse goes out of the scope of this element, it will go back to its initial state.
Structural Directives
Structural directives are used to change the structure of an element. It alters the layout of DOM by adding, replacing, or removing the element.
Example
App.component.ts
- <div [ngStyle]="{'width':'450px', 'margin-left':'150px','border':'4px solid #7142f4'}">
- <h3 [ngStyle]="{'color':'#42f46e','font-size':'26px'}">
- {{name}}
- </h3>
- <h3>I am working on these technologies</h3>
- <table [ngClass]="'table'">
- <tr><th>Technology</th><th>Experiences</th></tr>
- <!-- ngFor Exampl -->
- <tr *ngFor="let data of technology">
- <th>{{data.name}}</th><th>{{data.experience}}</th>
- </tr>
- </table>
- <input type="button" (click)="toggle()" value="Toggle Div"/>
- <br/>
-
- <!-- ngIf Exampl -->
- <div *ngIf="show">
- <div appCustom [inputbackgroundColor]="'pink'" [pankaj]="'36px'">This is a Custom Directive</div>
- </div>
- <br/>
- <input type="text" name="data" [(ngModel)]="count"/>
- <br/>
-
- <!-- ngSwitch Exampl -->
- <div [ngSwitch]="count">
- <p *ngSwitchCase="10">Your Value is 10 </p>
- <p *ngSwitchCase="100">Your Value is 100 </p>
- <p *ngSwitchDefault>Your Value is Not 10 or 100 </p>
- </div>
- </div>
App.component.ts
- import { Component,Input,Output,EventEmitter } from '@angular/core';
-
-
- @Component({
- selector: '[app-root]',
- templateUrl: './app.component.html',
- styleUrls: ['./app.component.css']
- })
-
-
- export class AppComponent {
- name:String = 'This is directive example';
- count:number=10;
- show:boolean=true;
- toggle(){
- this.show=!this.show;
- }
-
- ChangeValue(data:String){
- this.name=data;
- }
-
- technology=[
- {name:"Asp.NET MVC", experience:"1 Years"},
- {name:"Android", experience:"1 Years"},
- {name:"Ionic", experience:"6 Months"},
- {name:"Angular", experience:"1 Years"},
- {name:"Node.js", experience:"6 Months"}
- ];
-
-
- }
In the above code we are using “*ngFor” directive and displaying a table data. “*ngFor” directive iterates through a loop and instantiates a template each time.
“*ngIf” directive shows and hides the DOM element as per expression value passed in the directives.
In the above line of code, we are using a “*ngIf” directive and according to the value of “show” variable, it takes decision if the div will display or hide. We are calling a “toggle()” method on click of button and in this method, we are changing the value of “show” variable.
“ngSwitch” directives work as switch statement of any other languages. It takes an expression and matches this expression value for each nested element. If any nested element matches the value, then corresponding DOM element will be displayed. If any nested element doesn’t match the expression value, then the default DOM will be displayed.
In these lines of code, we created a “ngSwitch”,”*ngSwitchcase” structure hierarchy and bound the value of “count” model to “ngSwitch” directive. Now, which “p” element will display directly depends on the value of “count” and “*ngSwitchCash” that match the value of “count” model.
Create a custom structure directive
Now, let's create an “ngNif” structure directive. This structure directive opposes the “ngIf” directive. So, add a new directive named as “ngNif”.
Add the below code in your directive's file.
- import { Directive,TemplateRef,ViewContainerRef,Input } from '@angular/core';
-
- @Directive({
- selector: '[appNgNif]'
- })
- export class NgNifDirective {
-
- @Input() set appNgNif(value:boolean){
- if(!value){
- this.viewRef.createEmbeddedView(this.temRef);
- }
- else{
- this.viewRef.clear();
- }
- }
- constructor(private temRef: TemplateRef<any>, private viewRef: ViewContainerRef) {
-
- }
-
- }
In these lines, we defined the selector name(“[appNgNif]”) for directive. The directive's selector is typically the directive's attribute name in square brackets.
A structure directive creates an embedded View and inserts that in View container, adjacent to the element. To access the embedded View, we require " TemplateRef” class and for View container, we require “ViewContainerRef” class.
A View is a fundamental building block of the application UI. It is the smallest grouping of elements created and destroyed together. ViewContainerRef class provides a container that can contain two kinds of Views - Host Views are created by instantiating a component via createComponent, and Embedded Views are created by instantiating an embedded template via createEmbeddedView.
Now, our custom directives need to bind true and false property to “[appNgNif]”, that means we need an “appNgNif” input property.
In these lines of code, we created “appNgNif” set property which takes value parameter of Boolean type. In this property, we added embeddedView in ViewContainerRef if value of parameter is “false”, else we need to make ViewContainerRef empty.
Now, add the below lines in html template where you want to use this structure directive.
- <div [ngStyle]="{'width':'450px', 'margin-left':'150px','border':'4px solid #7142f4'}">
- <h3 [ngStyle]="{'color':'#42f46e','font-size':'26px'}">
- {{name}}
- </h3>
- <h3>I am working on these technologies</h3>
- <table [ngClass]="'table'">
- <tr><th>Technology</th><th>Experiences</th></tr>
- <!-- ngFor Exampl -->
- <tr *ngFor="let data of technology">
- <th>{{data.name}}</th><th>{{data.experience}}</th>
- </tr>
- </table>
- <input type="button" (click)="toggle()" value="Toggle Div"/>
- <br/>
-
- <!-- ngIf Exampl -->
- <div *ngIf="show">
- <div appCustom [inputbackgroundColor]="'pink'" [pankaj]="'36px'">This is a Custom Directive</div>
- </div>
- <br/>
-
- <div *appNgNif="show">
- <h2>NgNiF Example</h2>
- <div appCustom [inputbackgroundColor]="'red'" [pankaj]="'36px'">This is a ngNif Directive</div>
- </div>
-
- <br/>
- <input type="text" name="data" [(ngModel)]="count"/>
- <br/>
-
- <!-- ngSwitch Exampl -->
- <div [ngSwitch]="count">
- <p *ngSwitchCase="10">Your Value is 10 </p>
- <p *ngSwitchCase="100">Your Value is 100 </p>
- <p *ngSwitchDefault>Your Value is Not 10 or 100 </p>
- </div>
- </div>
When the value of “show” property becomes true, the “*ngIf” will show the div and “*appNgNif” will hide the div.
When “show” becomes false, the “*ngIf” will hide the div and “*appNgNif” will show the div.
Conclusion
Today, we learned about different types of directives and also created custom attributes and structure directives. I hope you liked this article. In the next article, we will cover some other concepts of Angular 2.