Angular2 Power Tools
Setup
Stash away any items not needed for this lab
git stash
Checkout the repo at the start tag
git checkout tags/lab/powertools/start -b feature/powertools-lab
Start the local angular-cli server:
ng serve
Start the Data Server in new tab/console (if not already running)
npm run start-api
you should see: NG Live Development Server is running on http://localhost:4200.
A login should load! Let's get to work!
Templates
What is a template?
In other technologies:
Java/JSP
<%@ taglib uri='/WEB-INF/tlds/template.tld' prefix='template' %>
<html>
<head>
<title><template:get name='title'/></title>
</head>
<body background='graphics/background.jpg'>
<table>
<tr valign='top'><td><template:get name='sidebar'/></td>
<td>
<table>
<% for(int i = 0; i < 10; i++) { %>
<tr><td><%=getMyValue(i)%></td></tr>
<% } %>
</table>
</td>
</tr>
</table>
</body></html>
Python
<table>
<%
for item in items:
%>
<tr>
<th>Name</th>
<td><%= item.name %></td>
</tr>
<%
%>
</table>
Angular 2:
<template let-message let-last="last" ngFor [ngForOf]="messages">
<a md-list-item>
<md-icon md-list-avatar>{{message.icon}}</md-icon>
<h3 md-line>{{message.title}}</h3>
<h4 md-line>{{message.firstname}} {{message.lastname}}</h4>
<p md-line>{{message.description}}</p>
...
</a>
<md-divider md-inset></md-divider>
</template>
From Angular Documentation:
HTML is the language of the Angular template:
<h1>Hello Angular</h1>
Almost all HTML syntax is valid template syntax. The <script>
element is a notable exception; it is forbidden, eliminating the risk of script injection attacks.
Some legal HTML doesn't make much sense in a template. The <html>, <body>, and <base>
elements have no useful role. Pretty much everything else is fair game.
NgFor
ngFor is a repeater directive.
Similar behavior as:
for (x in objects) { ... }
Example:
<template ngFor [ngForOf]="messages">
Variation:
<li *ngFor="let message of messages; let i = index">...</li>
ngFor can only be applied to a <template>
. *ngFor is the short form that can be applied to any element and the <template>
element is created implicitly behind the scene.
A <template>
is an HTML5 element and is a mechanism for holding client-side content that is not to be rendered when a page is loaded. (like a hidden container of content)
Let's try it!
Part 1 - NgFor
First go to covalent-training/src/app/overview/overview.component.ts
On line 12 you see the templateUrl
@Component({ selector: 'teradata-overview', templateUrl: './overview.component.html', styleUrls: ['./overview.component.scss'], })
This is the html file that will contain all the template code
- Let's open it up. Go to covalent-training/src/app/overview/overview.component.html
This is the template file that is used to generate the hard coded messages list
- Find the section on line 16 that says:
<md-nav-list> <a md-list-item> <md-icon md-list-avatar>account_box</md-icon> <h3 md-line>Message title goes here</h3> <h4 md-line>Firstname Lastname</h4> <p md-line>Message description goes here and it can be pretty long. At some point do we want the text to truncate...</p> ... </a>
- Replace all the hard coded list items between
<md-nav-list> ... </md-nav-list>
To instead be an NgFor repeater like this:
<md-nav-list> <template ngFor [ngForOf]="messages"> <a md-list-item> <md-icon md-list-avatar>account_box</md-icon> <h3 md-line>Message title goes here</h3> <h4 md-line>Firstname Lastname</h4> <p md-line>Message description goes here and it can be pretty long. At some point do we want the text to truncate...</p> <div flex="none" class="md-caption tc-grey-600">3 min ago</div> <span class="push-left-sm"> <button md-icon-button [mdMenuTriggerFor]="menu"><md-icon>more_vert</md-icon></button> <md-menu #menu="mdMenu" x-position="before"> <button md-menu-item> <md-icon>edit</md-icon> <span>Edit</span> </button> <button md-menu-item> <md-icon>cancel</md-icon> <span>Delete</span> </button> </md-menu> </span> </a> <md-divider md-inset></md-divider> </template> </md-nav-list>
At this point you should have deleted most of what was in lines 38 - 162. Notice all the repeated hard coded md-list-item have been consolidated down to one wrapped by ngFor.
Take a look at covalent-training/src/app/overview/overview.component.ts lines 18 and 29. Here you will notice the messages being pulled via http from the messagesServices. On line 18 is the array that holds the data:
messages: IMessage[];
In covalent-training/src/app/overview/overview.component.html notice the ngForOf that will loop over that same messages array:
<template ngFor [ngForOf]="messages">
Part 2 - Interpolation and Expressions
If needed you can checkout at this tag in lab. You don't need to checkout this tag if you successfully completed Part 1.
git checkout tags/lab/powertools/ngfor
What is Interpolation?
You use interpolation to weave calculated strings into the text between HTML element tags.
Let's try it. Go to covalent-training/src/app/overview/overview.component.ts line 19 and add:
title: string = 'messages';
Go to covalent-training/src/app/overview/overview.component.html
On line 13 change:
<md-card-title>Messages</md-card-title>
To:
<md-card-title>{{title}}</md-card-title>
Notice the Card Title now becomes lowercase:
messages
What are Expressions?
Expressions are the material between the braces that Angular first evaluates and then converts to a string.
Let's try it. Go to covalent-training/src/app/overview/overview.component.html
On line 13 change:
<md-card-title>{{title}}</md-card-title>
To:
<md-card-title>{{messages ? messages.length : 0}} {{title}} from {{1 + 1}} years ago or more</md-card-title>
Notice the Card Title now becomes:
10 messages from 2 years ago or more
Let's break this apart
- We are displaying the length of the messages array in covalent-training/src/app/overview/overview.component.ts line 18
- We are using displaying the title from covalent-training/src/app/overview/overview.component.ts line 19
- And finally we are evaluating the expression 1 + 1 and displaying the result 2
ngFor with Interpolation
Now let's use Interpolation with the ngFor we created
Go to covalent-training/src/app/overview/overview.component.html
Starting on line 17 change this:
<template ngFor [ngForOf]="messages"> <a md-list-item> <md-icon md-list-avatar>account_box</md-icon> <h3 md-line>Message title goes here</h3> <h4 md-line>Firstname Lastname</h4> <p md-line>Message description goes here and it can be pretty long. At some point do we want the text to truncate...</p> <div flex="none" class="md-caption tc-grey-600">3 min ago</div>
To this:
<template let-message ngFor [ngForOf]="messages"> <a md-list-item> <md-icon md-list-avatar>{{message.icon}}</md-icon> <h3 md-line>{{message.title}}</h3> <h4 md-line>{{message.user}}</h4> <p md-line>{{message.desc}}</p> <div flex="none" class="md-caption tc-grey-600">{{message.created}}</div>
Let's break this apart
- We added the
let-message
to the ngFor on the template. This assigns each object when looping through messages to a variable name message. - We can now use the message variable inside our Interpolation Expressions
{{message.icon}}, {{message.title}}, {{message.user}}, {{message.desc}}, and {{message.created}}
are allow evaluated and allow us to display attributes for the message object
- We added the
The end result now displays the list of message objects and their attributes:
Part 3 - NgFor with index
If needed you can checkout at this tag in lab. You don't need to checkout this tag if you successfully completed Part 2.
git checkout tags/lab/powertools/interpolation
What is it?
The index property of the NgFor directive context returns the zero-based index of the item in each iteration.
Similar behavior as:
for (var i = 0; i < list.length; i++) { ... }
Example:
<template let-index="index" ngFor [ngForOf]="messages">
Variation:
<li *ngFor="let message of messages; let i = index">...</li>
(Same reasoning as above)
Let's try it. Go to covalent-training/src/app/overview/overview.component.html
On line 17 change:
<template let-message ngFor [ngForOf]="messages">
To:
<template let-message let-index="index" ngFor [ngForOf]="messages">
On line 20 change:
<h3 md-line>{{message.title}}</h3>
To:
<h3 md-line>{{index}}. {{message.title}}</h3>
Notice the index is now displayed next to the title on each row:
Part 4 - NgIf and Last
If needed you can checkout at this tag in lab. You don't need to checkout this tag if you successfully completed Part 3.
git checkout tags/lab/powertools/ngforwithindex
What is NgIf?
- You can add or remove an element from the DOM by applying an NgIf directive to that element
Similar behavior as:
if(somethingTrue) { ... }
What is Last?
A variable within ngFor that is set to a boolean value indicating whether the item is the last one in the iteration.
Let's try it. Go to covalent-training/src/app/overview/overview.component.html
On line 17 change:
<template let-message let-index="index" ngFor [ngForOf]="messages">
To:
<template let-message let-index="index" let-last="last" ngFor [ngForOf]="messages">
On line 38 change:
<md-divider md-inset></md-divider>
To:
<md-divider *ngIf="!last" md-inset></md-divider>
To note: unlike other hiding techniques when using CSS, ngIf completely removes the element from the DOM
By adding this ngIf that checks to see if we aren't on the last element, we no longer get the a double line at the end:
Before:
After:
Part 5 - Pipes
If needed you can checkout at this tag in lab. You don't need to checkout this tag if you successfully completed Part 4.
git checkout tags/lab/powertools/ngifandlast
What is a Pipe?
(|) The result of an expression might require some transformation before you're ready to use it in a binding. For example, you might display a number as a currency, force text to uppercase, or change a date to a specific format
Let's try it. Go to covalent-training/src/app/overview/overview.component.html
On line 23 change:
<div flex="none" class="md-caption tc-grey-600">{{message.created}}</div>
To:
<div flex="none" class="md-caption tc-grey-600">{{message.created | date:'medium'}}</div>
This takes the message.created date and formats it to 'yMMMdjms' (e.g. Sep 3, 2010, 12:05:08 PM)
- There are several date options you can pass in besides medium: