Angular

Directives

Pipes

Directive

Class that attaches to an existing DOM element and modifies its appearance, behavior or adjacent elements structure

Uses @Divective decorator

Directives

  • Components
  • *Structural directives
  • [Attribute directives]
<my-component></my-component>
<div *myDirective></div>
<div myDirective></div>
<div [myDirective]></div>
<div (myDirective)></div>
<div [(myDirective)]></div>

Getting started

$ ng g directive directives/new-stuff
@NgModule({
  declarations: [
    AppComponent,
    -->NewStuffDirective,
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
import { Directive } from '@angular/core';

@Directive({
  selector: '[appNewStuff]'
})
export class NewStuffDirective {

  constructor() { }

}

Attribute directives

Designed to modify appearance or behavior of an element

<div myDirective></div>
<div [myDirective]></div>
<div (myDirective)></div>
<div [(myDirective)]></div>

Attribute directives

Default dependencies

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

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

  constructor(private elementRef: ElementRef, private renderer2: Renderer2) { }
}

Demo

Structural Directives

Designed to change the DOM layout by adding or removing DOM elements

<div *myDirective></div>

<ng-template>

Angular element for rendering HTML which is never displayed directly

<p>Hip!</p>
<ng-template>
  <p>Hip!</p>
</ng-template>
<p>Hooray!</p>

The asterisk (*) prefix

*ngIf

<div *ngIf="hero" class="name">{{hero.name}}</div>

<ng-template [ngIf]="hero">
  <div class="name">{{hero.name}}</div>
</ng-template>

*ngIf

else mycrosyntax

<div class="feed" *ngIf="posts; else loading">
  ... 
</div>

<ng-template #loading>
    <div>Loading...</div>
</ng-template>

*ngSwitch

<div [ngSwitch]="hero?.emotion">
  <app-happy-hero    *ngSwitchCase="'happy'"    [hero]="hero"></app-happy-hero>
  <app-sad-hero      *ngSwitchCase="'sad'"      [hero]="hero"></app-sad-hero>
  <app-confused-hero *ngSwitchCase="'confused'" [hero]="hero"></app-confused-hero>
  <app-unknown-hero  *ngSwitchDefault           [hero]="hero"></app-unknown-hero>
</div>
<div [ngSwitch]="hero?.emotion">
  <ng-template [ngSwitchCase]="'happy'">
    <app-happy-hero [hero]="hero"></app-happy-hero>
  </ng-template>
  <ng-template [ngSwitchCase]="'sad'">
    <app-sad-hero [hero]="hero"></app-sad-hero>
  </ng-template>
  <ng-template [ngSwitchCase]="'confused'">
    <app-confused-hero [hero]="hero"></app-confused-hero>
  </ng-template >
  <ng-template ngSwitchDefault>
    <app-unknown-hero [hero]="hero"></app-unknown-hero>
  </ng-template>
</div>

*ngFor

<div *ngFor="let hero of heroes; let i=index; let odd=odd">
  ({{i}}) {{hero.name}}
</div>

<ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd">
  <div>({{i}}) {{hero.name}}</div>
</ng-template>

*ngFor Microsyntax

let [template input variable] of [array]; let myVariable = [variable]

Variable Meaning 
index Index of current element (number, starts 0) 
first Is element first (boolean)
last Is element last (boolean) 
even Is element even (boolean) 
odd  Is element odd (boolean)

Structural Directives

Custom UnlessDirective example

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

/**
 * Add the template content to the DOM unless the condition is true.
 */
@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
  private hasView = false;

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

  @Input() set appUnless(condition: boolean) {
    if (!condition && !this.hasView) {
      this.viewContainer.createEmbeddedView(this.templateRef);
      this.hasView = true;
    } else if (condition && this.hasView) {
      this.viewContainer.clear();
      this.hasView = false;
    }
  }
}
<p *appUnless="condition" class="unless a">
  (A) This paragraph is displayed because the condition is false.
</p>

<p *appUnless="!condition" class="unless b">
  (B) Although the condition is true,
  this paragraph is displayed because appUnless is set to false.
</p>

Structural Directives

Custom UnlessDirective example

Demo

Pipes

Class that allow changing data inside of a template

Uses @Pipe decorator

What are pipes

const now = new Date();

function formatDate(date) {
    const month = date.getMonth() + 1;
    return `${date.getDate()}.${month < 10 ? '0' : ''}${month}.${date.getFullYear()}`
}
{{ now | date: 'dd.MM.yyyy' }}

JavaScript

Angular

Getting started

$ ng g pipe pipes/filter-by
@NgModule({
  imports: [ BrowserModule ],
  declarations: [
    -->FilterByPipe,
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule{ }
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'myCustomPipe'
})
export class FilterByPipe<T> implements PipeTransform {

  transform(items: T[], param1: string, param2: string){
    // ...
  }

}

Using pipes

<p>{{ expression | pipeName:param1:param2 }}</p>

General syntax

Chaining pipes

<p>{{ 'Angular' | slice:3 | uppercase }}</p>

Angular -> ular -> ULAR

Using pipes inside a code

import { AgePipe } from './pipes/custom.pipe';
import { DatePipe } from '@angular/common';

@Component({
  selector: 'my-app',
  templateUrl: '../app/app.html',
  providers: [AgePipe, DatePipe],
})
export class AppComponent implements OnInit {
  public currentDay = this.datePipe.transform(new Date(), 'yyyy/MM/dd');
  public employees: Employee[];
  private allEmployees = employees; // data stored somewhere

  constructor(private datePipe: DatePipe, private agePipe: AgePipe) {}

  public ngOnInit(): void {
    this.employees = this.agePipe.transform(employees, 30);
  }
}

Demo

Pure and impure pipes

Pure Pipes Angular executes a pure pipe only when it detects a pure change to the input value.

Pure pipe

A pure change is either a change to a primitive input value (String, Number, Boolean, Symbol) or a changed object reference (Date, Array, Function, Object).

Pipes are pure by default.

Pure and impure pipes

Angular executes an impure pipe during every component change detection cycle.

Impure pipe

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'myCustomPipe',
  -->pure: false  
})
export class FilterByPipe<T> implements PipeTransform {

  transform(items: T[], param1: string, param2: string){
    // ...
  }

}

An impure pipe will be called a lot, as often as every keystroke or mouse-move.

Demo

Useful links

Q & A

Angular. Directives & Pipes

By Pavel Razuvalau

Angular. Directives & Pipes

  • 1,022