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:
String
Array
Object
1. String Binding
No explanation here. This is pretty easy with sample code here.
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>
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}`
}
}
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>
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>
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 directives 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.
Quote:
@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 canonical 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.
CodeProject