Directives in Angular (Part 2)

This post is a sequence of the previous directives part 1. In this post, I’ll just explain what each directive does.

ngClass

ngClass directive changes the class attribute of the element when a value is supplied.

This binding can happen in 3 different ways

  1. String
  2. Array
  3. Object

1. String binding:

No explanation here. This is pretty easy with sample code here.


//our root app component
import {Component} from '@angular/core'
@Component({
selector: 'my-app',
template: `
<div>
<p ngClass="text-center">ngClass string binding here</p>
</div>
`,
styles: [
`
.text-center{
text-align: center;
}
`
]
})
export class App {
constructor() {
}
}

Not a lot of magic here. We’ve just added our CSS class in the styles and accessed with ngClass directive here. Binding with static class name won’t bring much of the advantage of ngClass directive, it is better to use normal class attribute in this case.

2. Array binding

In this case, we’ll just assign the ngClass to an array of CSS class names. It’s the same code again but just a change in the assignment.

Example:


<p [ngClass]="['text-center', 'bold-text']">string binding here</p>

text-center and bold-text are our CSS classes available and we bind those classes to have our template reflect styles.

3. Object binding

In this Object binding, we’ll assign ngClass with an object containing of keys (which are CSS classes) and values of those classes as true/false. So, if a property is true, then the CSS class will be applied and if it’s false it won’t apply that class name to the tag.


@Component({
selector: 'my-app',
template: `
<div>
<p [ngClass]="{ 'text-center': true, color: true }">ngClass string binding here</p>
</div>
`,
styles: [
`
.text-center{
text-align: center;
}
.bold-text {
font-weight: bold;
}
.color {
color: red;
}
`
]
})

Notice how I used text-color in the object. If the CSS class contains hypens or any special characters wrap it in single quotes.

ngStyle

ngStyle is similar to style property in CSS. Unlike normal style attribute for HTML elements, ngStyle will have object literal syntax. This object can be passed from the component dynamically or can be hardcoded within the object as well.

Example:


<div [ngStyle]="{'color': 'red', 'font-weight': 'bold'}">content</div>

view raw

ngstyle.html

hosted with ❤ by GitHub

If the styles are dynamic then we can just pass the object to ngStyle from the component export and it will apply the styles.


import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<div>
<h2 [ngStyle]="styles">Hello {{name}}</h2>
</div>
`,
})
export class App {
name:string;
border = '2px solid green';
styles = {
'color': 'red',
'font-weight': 'bold',
'border': this.border
};
constructor() {
this.name = `Angular! v${VERSION.full}`
}
}

view raw

ngStyle.demo.ts

hosted with ❤ by GitHub

In the above code observe the border property. We can still have our dynamic properties added to that object literal.

demo

 Attribute directive (revisited)

Recollect the example of attribute directive that we used in part 1 of the directives.

We’ll just extend the functionality of that colorMe directive. Let’s add some events to the directive using HostListener decorator.

Host Listener, listens to the events on the directive that we’ve created.

Use case: We’ll just add click and double click events to the directive. On single click, we’ll apply red color to the target element and on double click we’ll apply green color to it.


import { Directive, ElementRef, HostListener } from '@angular/core'
@Directive({
selector: '[colorMe]'
})
export class ColorDirective{
constructor(private el: ElementRef){
el.nativeElement.style.color = 'gray';
}
@HostListener('click') onClick() {
this.el.nativeElement.style.color = 'red';
}
@HostListener('dblclick') onDblClick() {
this.el.nativeElement.style.color = 'green';
}
}

As you can see the default color of our directive will be gray and when you click on the text it tuns into ‘red’ and if you double click on the text then it tuns ‘green’.

Demo of directive using Host Listener

Structural directives:

ngIf, ngFor and ngSwitch are the built-in structural directives provided by angular.

ngIf:

ngIf is pretty simple. It takes a boolean expression and will hide/show the DOM element with respective to the boolean expression.

Example:


<p *ngIf="visible">visible element</p>
<p *ngIf="!visible">visible element</p>

view raw

ngIfSyntax.html

hosted with ❤ by GitHub

The above example is a just a toggle between two elements using visible as an expression for ngIf. The second p tag is not actually visible in the DOM. Why?

Note: when the expression inside of ngIf is false, angular will remove that element from DOM, detatches events, detaches from component change detection and destroys the element.

ngSwitch:

ngSwitch is similar to JavaScript switch statement except the syntax of Angular.

Example:


<container-element [ngSwitch]="switch_expression">
<some-element *ngSwitchCase="match_expression_1">…</some-element>
<some-element *ngSwitchCase="match_expression_2">…</some-element>
<some-other-element *ngSwitchCase="match_expression_3">…</some-other-element>
<some-element *ngSwitchDefault>…</some-element>
</container-element>

view raw

ngSwitch.html

hosted with ❤ by GitHub

the ngSwitch is the switch keyword in javascript. ngSwitchCase is case statement in switch and ngSwitchDefault is the default option in switch case.

ngFor/ngForOf:

ngFor is a like for loop in JavaScript but with different syntax of angular.

Example:


<div *ngFor="let item of groceries; let i=index;">
({{i}}) {{item.name}}
</div>

We will iterate through items in the list or object and print them or use them to supply arguments to other child elements.

ngFor is a selector of ngForOf directive. But we need both these directive to be present on an element to display it.

Why is it? See the source code. Check the selector in the source code. FYI here is the selector mentioned in the source.

@Directive({selector: [ngFor][ngForOf]})

Though we don’t write ngForOf angular will generate by itself when we use *ngFor. *ngFor is not actually what the compiler sees it. When we use *ngFor, then angular compiler de-sugars into cannonical form which has both the attributes on the element.

The cannonical form:

Asterisk is the syntactic sugar for translating to template syntax.

So, if we have *ngFor code as


<div *ngFor="let item of groceries; let i=index;">
({{i}}) {{item.name}}
</div>

then it is translated to


<div template="ngFor let item of groceries" let-i="index">
({{i}}) {{item.name}}
</div>

In the translated code we don’t have *(asterisk’s) anymore. The above code is again de-sugared into template syntax.


<template ngFor let-item [ngForOf]="groceries" let-i="index">
({{i}}) {{item.name}}
</template>

Now, in the final template syntax we have both ngFor and ngForOf keywords within the template. ngFor is just a marker here and ngForOf is an input to the directive that points list of items. This process of translating the string to template syntax is called Microsyntax.

More on microsyntax.

Leave a comment