Angular 2 Attribute Directives

Posted by Andy Armstrong on 12/7/2016

Introduction

AngularJS really introduced the concept of organizing and extending the DOM for use in real web applications. AngularJS 1.x brought us the idea of a Directive, or a way to indicate that a DOM element was “special” and will have a behaviors or an appearance that will be controlled by your code. AngularJS 2 took this idea and ran with it, but this also means we need to explain some stuff. We now have 3 tools at our disposal for interacting with the DOM: Components, Structural Directives and Attribute Directives.

Components, which you should have at least read about by now, are the most basic of the angular building blocks. Everything is a component and all components have directives; components are created from one or more directives. Directives are the method to identify a component’s behavior or associate a variable to a component.

Structural Directives are used to add or remove elements from the DOM. Common examples are *ngIf or *ngFor. These directives allows you manipulate a component based on a variable value or allow a component to iterate a series of values.

Finally, we have Attribute Directives. Attribute directives allow you to attach a behavior to an element or affect it’s appearance and re-use this throughout your application or package it up as something you use in all your projects.

Using Attribute Directives you can create a stylized DIV tag that formats all text and adds an event listener to change the color when the user mouses over the text. Show off your example code with some syntax highlighting!

I should also note that Attribute Directives can access and manipulate application values, but primarily are focused on affecting the component they have been attached. Think of this as more like CSS Selector Class on steroids. Make sure you do the “real math” of your application in your components.

Anatomy of an Attribute Directive & How to use it

Attribute Directives can be simple or complex. The simplest example of an Attribute Directive could be a simple CSS property attached to a P Tag:

<p [style.background]="'red'">I'm red!</p>

Anything more complex than the above example requires a little more wiring. Let’s look at an commented example from the official docs called “Highlight”:

// Import some stuff from the core library
import { Directive, ElementRef, Input, Renderer } from '@angular/core';

// create a Directive to decorate. To prevent confusion let's call this myHighlight to 
// illustrate the fact this this is a custom appearance
@Directive({ selector: '[myHighlight]' })

export class HighlightDirective {

    /* 
    This is a pretty simple example, we just need a constructor. Pass the element we wish to affect in as "el" and make sure we interact with the DOM renderer with the obvious name of "renderer"
    */
    constructor(el: ElementRef, renderer: Renderer) {

       /* 
       Set the element's Background Color CSS property to Yellow, as though we "highlighted" it with a marker.

       Note we reference the element itself as el.nativeElement so we actually update the rendered DOM model itself.
       */
       renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'yellow');
    }

}

Use and apply your custom directive attribute in your application
<p myHighlight>Highlight me!</p>

Some Attribute Directive Examples

Italic & Underline

A very simple example showing how we can make something italic, and underlined, using a simple attribute directive.

@Directive({ selector: '[alItalic]' })

export class ItalicDirective {
 
  constructor(el: ElementRef, renderer: Renderer) {
    renderer.setElementStyle(el.nativeElement, 'fontStyle', 'italic');
    renderer.setElementStyle(el.nativeElement, 'textDecoration', 'underline');
  }
 
}

Plnkr

Blink

We can also bring back the much missed BLINK tag using an attribute directive. This example illustrates how we can actually encapsulate some logic and manipulate the DOM element’s CSS with this logic by using an attribute directive that can be placed on any block element.

@Directive({ selector: '[alBlink]' })

export class BlinkDirective {
  
    constructor(el: ElementRef, renderer: Renderer) {
      setInterval(() => { 
        let style = "hidden";
        if(el.nativeElement.style.visibility && el.nativeElement.style.visibility == "hidden") {
          style = "visible";
        }
        renderer.setElementStyle(el.nativeElement, 'visibility', style); 
      }, 750);
    }
    
}

Plnkr

Detected User Event – Click

Finally, here’s an example where we can listen for a user event (click) on an element by simply using an attribute directive.

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

@Directive({ selector: '[alClick]' })

export class ClickDirective {
  
  private _el: ElementRef;
  
  constructor(el: ElementRef, renderer: Renderer) { 
    this._el = el;
  }

  @HostListener('click') onClick() {
    let str = this._el.nativeElement.innerHTML;
    alert("innerHTML from the element you clicked: " + str);
  }
    
}

Plnkr

Conclusion

We really only scratched the surface of what you can do with Attribute Directives. AngularJS has always been a framework that allowed you to organize and extend your DOM based applications, but AngularJS 2 has taken this to a whole new level.

Hope you enjoyed this post!