Ad

Angular the series Part 5: Directive

    

    Directive help us extends the power of HTML by giving it new syntax. Each directives has a name - either one from the Angular predefined or a custom one which can be called anything. We can use Directive to manipulate the DOM. We can add a DOM element, or remove an existing one, or change the way it looks, and so on.

In Angular, we have 3 types of Directive:


Component

    Component is the most common of the three directives. Component is a type of directive with a template along with it. We have already discussed about this in the last article. You can find it here.


Attribute Directives

Attribute Directives manipulate the DOM by changing its behavior and appearance

1. ngClass

It is use to add and remove CSS classes on a HTML element. We can use with

  • string expression: the CSS classes listed in the string will be added to the element
my-new-component.component.html
<p [ngClass]="'class1 class2'">An example for ngClass</p>
my-new-component.component.css
.class1 {
  background-color: red;
  color: white;
}
.class2 {
  font-size: 13px;
}
  • array expression: the CSS classes declared as array elements will be added
my-new-component.component.html
<p [ngClass]="['class1', 'class2']">An example for ngClass</p>
  • object expression: an object with keys are CSS classes will be added when the expression given in the value is a truthy value, otherwise they will be removed.
my-new-component.component.html
<p [ngClass]="{'class1': true, 'class2': true, 'class3': false}">
    An example for ngClass
</p>

2. ngStyle

    Update style for the containing HTML element specified as key-value pairs. The key is a style name, and the value is an expression to be evaluated. For example:

my-new-component.component.html
<p [ngStyle]="{'background-color': isError ? 'red' : 'green'}">
    An example for ngStyle
</p>
my-new-component.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-my-new-component',
  templateUrl: './my-new-component.component.html',
  styleUrls: ['./my-new-component.component.scss']
})
export class MyNewComponentComponent implements OnInit {
  isError: boolean = false;

  constructor() { }

  ngOnInit(): void {
  }
}

3. Create a custom attribute directive

    Creating a custom directive is very similar to creating a component. You can either use Angular CLI or create manually. Every directives is defined using @Directive decorator. To create a new directive using Angular CLI, just run the command

ng generate directive <directive-name>

This command will create a new, generic directive definition in the folder where you run it. It will also declare that new directive in the root module for you.

highlight.directive.ts
import { Directive } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {

  constructor() { }

}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { MyNewComponentComponent } from './my-new-component/my-new-component.component';
import { HighlightDirective } from './highlight.directive';

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

    Every directives has a selector, just like the component. This selector is used to apply the directive to the elements in your template. You can change that selector to any names you want, but just make sure it does not duplicate with the Angular predefined directives and the other directives you created.

Let implement some logic for the highlight.directive.ts to change background of element to yellow when this directive is applied.

highlight.directive.ts
import { Directive, ElementRef } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {

  constructor(private el: ElementRef) { }

  ngOnInit() {
      this.el.nativeElement.style.backgroundColor = 'yellow';
  }

}

And use it in the template

my-new-component.component.html
<p appHighlight>Custom Attribute Directive Sample</p>


Structural Directives

Structural Directives change the structure of the DOM based on the specified conditions or data.

1. ngFor

    Render a template for each item in a collection. This directive is placed on an element, which will become the parent of the cloned template.

my-new-component.component.html
<ul>
  <li *ngFor="let person of people; let i = index">
      {{ i + 1 }} - {{ person.name }}
  </li>
</ul>
my-new-component.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-my-new-component',
  templateUrl: './my-new-component.component.html',
  styleUrls: ['./my-new-component.component.scss']
})
export class MyNewComponentComponent implements OnInit {
  people: any[] = [
      { name: "Williams" },
      { name: "Elise" },
      { name: "Thomas" },
      { name: "Phillip" },
      { name: "David" },
  ];

  constructor() { }

  ngOnInit(): void {
  }
}

2. ngIf

    ngIf directive will conditionally include a template based on the value of an expression coerced to boolean. It works like the if statement. When the expression is true, Angular will render the template defined in then clause. Otherwise, when the expression is false or null, Angular will render the template defined in else clause. If we don't define the template for else, it will be a blank one.

my-new-component.component.html
<div *ngIf="isError; then thenBlock; else elseBlock"></div>
<ng-template #thenBlock>This will show when isError equals to true</ng-template>
<ng-template #elseBlock>This will show when isError equals to false</ng-template>
my-new-component.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-my-new-component',
  templateUrl: './my-new-component.component.html',
  styleUrls: ['./my-new-component.component.scss']
})
export class MyNewComponentComponent implements OnInit {
  isError: boolean = false;

  constructor() { }

  ngOnInit(): void {
  }
}

A shorthand form of ngIf is *ngIf="condition", without then and else clause.

my-new-component.component.ts
<div *ngIf="isError">This will show when isError equals to true</div>

3. Create a custom structural directive

    Let's create a new custom structural directive named unless. It is basically the opposite of ngIf. Again, you can either use Angular CLI or create manually.

Open the file we just created and implement some logic to display the content when the condition is false.

unless.directive.ts
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appUnless]'
})
export class UnlessDirective {
  @Input() set appUnless(condition: boolean) {
    if (!condition) {
      this.viewContainer.createEmbeddedView(this.templateRef);
    } else {
      this.viewContainer.clear();
    }
  }

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef
  ) { }

}

And use the directive in a template:

my-new-component.component.html<div *appUnless="false">
    This content will be displayed because the condition is false.
</div>