Directives

Directives: Hmmm … #

These are just classes that add extra behavior to elements ~ Angular docs.

Components are represented in HTML as elements. Directives are represented as attributes on those elements. A directive can also be applied on a simple HTML element, not just components.

Creating them #

You can create a directive class in a file like nice.directive.ts like so:

import { Directive, OnInit } from '@angular/core'

Directive({
    selector: '' // CSS style selector e.g. [nice-stuff]
    // the HTML would be like <somecomp nice-stuff></somecomp>
})
export class NiceDirective {

}

They need to be added to the declaration section of the ngModule where they will be used. They can get a reference to the element they were used on via the ElementRef service which can be added as a dependency.

Raw access to the DOM element can be gotten via the ElementRef object like so: ref.nativeElement.

Passing values to it #

To pass in some value you just set the value of the attribute. E.g. for a directive with a selector “sneaky-wookie”, do this: <div sneaky-wookie="some nice string"></div>. This can then be accessed via an @Input() property like so: @Input('sneaky-wookie') aliasName: string within the directive class.

An alias had to be used since the directive selector had a ‘-’ in it.

Builtins #

Attribute #

Some examples are: ngClass ngStyle

Structural #

Some basic stuff has been covered here in the docs: ngIf ngFor

<a *ngIf="expr"></a> is really a shortcut, it expands to: <ng-template [ngIf]="expr"><a></a></ng-template>.

It’s possible to have an else block like so:

<a *ngIf="expr; else theOtherBlock">first</a>
<a #theOtherBlock>second</a>

If you want to be consistent you could write that as:

<div *ngIf="expr; then theFirstBlock else theOtherBlock>
<a #theFirstBlock>first</a>
<a #theOtherBlock>second</a>
Does using a <div> there seem weird? It’s possible to use <ng-container> instead. It doesn’t even get output into the final HTML

Want to have an index while looping with ngFor? Do this:

<div *ngFor="let item of items; let i=index">{{i + 1}} - {{item.name}}</div>

When the list that ngFor is rendering changes, it’s possible to optimize the rendering by only rendering the elements that have changed (modified / removed / added). This is done with trackBy:

<div *ngFor="let item of items; trackBy: (i, d) => d.id">
  ({{item.id}}) {{item.name}}
</div>

ngFor has a bunch of local variables which can help reduce template code. They can be found in the docs but here is an example:

<li *ngFor="let user of users; index as i; count as c">
  {{user.name}} is {{i}} out of {{c}} in the list
</li>

Attribute #

How to make a custom one!
Start off with ng generate directive somecoolstuff. The base may not be enough, so set it up like this:

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

@Directive({
  selector: '[appSomecoolstuff]'
})
export class SomecoolstuffDirective {
    constructor(private el: ElementRef) {
        // can access DOM node with el.nativeElement
    }
    @HostListener('click') handler() {
        // do stuff to the element
    }    
}

It can be added to an element like this: <a appSomecoolstuff></a>. Multiple values can be passed to it using @Input() e.g.:

@Input() randomProp1: string;
@Input() randomProp2: number;

which can be used like so: <a appSomecoolstuff randomProp1="wowcool" [randomProp2]="1+2"></a>.

Structural #

These modify the DOM by adding / removing elements. Only one structural directive can be applied per element. It’s possible to make your own like so: ng g directive whatADirective. The class can be modified like this:

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

@Directive({ selector: '[appWhatADirective]'})
export class WhatADirectiveDirective {
  private someStuff = 'wow';

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

  @Input() set appWhatADirective(randomStuff: string) {
    // do some stuff to the view container
  }
}

which can then be used like so:

<p *wow="'somestring'">
maybe do something with this content here?
</p>

The translation between structural directive shortcuts and what Angular actually does can be found here