This article is part of a 10 Days series on the latest version of Angular. In this post, we will learn about Templates, Events, Models, Directives, etc.
If you are into this article, it means that you know how to:
- install NodeJs and get npm
- install TypeScript compiler and use it
- install lite-server and use it
- setup a basic Angular Project
- create a simple "
Hello World
" application using Angular
and:
- have fundamental knowledge on TypeScript
Today, we will take our Angular skill to the next level with more labs and demos. Let’s get started.
Pre-Setup
Before you continue with any demo, I want you to do two things.
- Open Command prompt, navigate to "TypeScriptFiles" folder and write "
tsc -w
" command to start TypeScript compiler in watch mode.
It will make sure that every time a TypeScript file gets changed, it automatically gets recompiled. There is no need for manual recompilation after every change.
- Open another Command prompt, navigate to "AngularProject" folder and write "
lite-server
" command to start the webserver.
It will automatically launch the browser (Internet Explorer). Copy the URL from the address bar, open Chrome and paste the same URL in the address bar.
(Note: Chrome is best when it comes to JavaScript debugging, if you want, you can do the testing in your favorite browser.)
Moving forward, anytime any of the files in the "AngularProject" folder get changed, the browser automatically gets refreshed. Automatic refresh is the power of "lite-server
".
Complete Series
- Day 1 – Part 1
- Day 1 – Part 2
- Day 2
- Day 3
- Day 4 – Part 1
- Day 4 - Execution trick
- Day 4 – Part 2
- Day 4 – Part 3
- Day 5 (Coming soon)
- Day 6 (Coming soon)
- Day 7 (Coming soon)
- Day 8 (Coming soon)
- Day 9 (Coming soon)
- Day 10 (Coming soon)
Contents
Lab 2 – Introduction to Template URL
In the last demo, we created "AppComponent
". Angular Component is a combination of two things.
- A TypeScript class called
AppComponent
– It’s called ViewClass
or Component
class. We will talk about real use of it very soon. - Template - Which is purely an HTML and represents our UI.
In the current demo, both of the above things are written in the same TypeScript file. Many people (including me) prefer to write HTML in an independent HTML file and have clear separation of concerns.
It can be done using "templateUrl
". Let’s see how.
Step 1 – Create Component Folder
Create a new folder called "AppComponent" inside the "AppModule" folder. (Just to recall "AppModule" is located inside "TypeScriptFiles\AppModule" folder.)
Step 2 – Move Component
Move "app.component.ts", "app.component.js" and "app.component.js.map" files into the "AppComponent" folder.
Step 3 – Correct the References
Change the import
statement in "AppModule
" as follows:
import {AppComponent} from "./AppComponent/app.component"
Complete AppModule
code looks like below:
import {NgModule} from "@angular/core"
import {AppComponent} from "./AppComponent/app.component"
import {BrowserModule} from "@angular/platform-browser"
@NgModule({
declarations:[AppComponent],
bootstrap:[AppComponent],
imports:[BrowserModule]
})
export class AppModule{
}
Step 4 – Compile and Test the Output
Just to make sure that everything is proper, let’s do the testing once. Go to the browser.
You should be able to see the following output:
Step 5 – Create Template File
Create a new file called "app.component.html" in the "AppComponent" folder and put the following content inside it:
<h1>Welcome to Learn Angular in 10 days series</h1>
<i>Here is the Day 3</i>
Step 6 – Attach Template to Component
Use "templateUrl
" option instead of "template
" option in the "Component
" decorator attached to "AppComponent
" class as follows:
import {Component} from "@angular/core"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
}
Step 7 - Compile and Test the Output
Go to the browser.
Check the error. As you can see, ‘app.component.html’ is searched in the root folder.
Step 8 – Change Template URL
"templateURL
" is relative but relative to "index.html" not to its TypeScript file. Change "templateURL
" to "./TypeScriptFiles/AppModule/AppComponent/app.component.html" as follows. The complete code will look like below:
import {Component} from "@angular/core"
@Component({
selector:'app-component',
templateUrl:'./TypeScriptFiles/AppModule/AppComponent/app.component.html'
}
)
export class AppComponent{
}
Step 9 - Compile and Test the Output
Go to the browser.
Lab 3 – Working with Relative URLS
In the last lab, we simply took out the HTML from TypeScript file and placed it in an independent HTML (template) file. The only problem was "templateUrl
" was relative to "index.html".
If you want to keep "templateUrl
" relative to the corresponding ".ts" file, then this lab is for you.
It can be achieved by using a SystemJs plugin called "systemjs-angular-loader.js". SystemJs has support for external plugins using which we can extend the existing behavior of SystemJs. "systemjs-angular-loader.js" dynamically converts "component-relative
" paths in "templateUrl
" to absolute paths.
Let’s do the demo.
Step 1 – Download the Plugin
This plugin was created by Angular team and it will be available in the quick start setup given by Angular team. Here is the link for the same:
Download the zip file from the above link and extract it. "systemjs-angular-loader.js" file is present inside "src" folder.
(We will have a detailed demo explaining this quick start project in future, for now let’s do everything manually and let’s understand the core of everything.)
Step 2 – Include Plugin
Copy the extracted plugin and paste it in the "AngularProject" folder. Now open "system.config.js" and add plugin support as follows:
...
packages: {
'TypeScriptFiles': {
defaultExtension: 'js',
meta: {
'./*.js': {
loader: 'systemjs-angular-loader.js'
}
}
},
rxjs: {
defaultExtension: 'js'
…
Check the new "meta
" option added.
Complete "system.config.js":
(function (global) {
System.config({
map: {
'@angular/core': '/node_modules/@angular/core/bundles/core.umd.js',
'@angular/common': '/node_modules/@angular/common/bundles/common.umd.js',
'@angular/compiler': '/node_modules/@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser':
'/node_modules/@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic':
'/node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': '/node_modules/@angular/http/bundles/http.umd.js',
'@angular/router': '/node_modules/@angular/router/bundles/router.umd.js',
'@angular/forms': '/node_modules/@angular/forms/bundles/forms.umd.js',
'rxjs':'/node_modules/rxjs',
},
packages: {
'TypeScriptFiles': {
defaultExtension: 'js',
meta: {
'./*.js': {
loader: 'systemjs-angular-loader.js'
}
}
},
rxjs: {
defaultExtension: 'js'
}
}
});
})(this);
Step 3 – Change Component
Change "templateUrl
" value to relative path as follows:
import {Component} from "@angular/core"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
}
Step 4 - Compile and Test the Output
Go to the browser.
As you can see, now the demo is working with a relative URL too.
Note
It’s not compulsory to use SystemJs as Module Loader for your Angular project. You can even go with "requireJs
" or something else too. In the case of other Module Loaders, you have to either go with earlier "Lab 2" approach for specifying URL or have to check your new Module loader documentation for such support.
I recommend you not to go too much in-depth about SystemJs right now and concentrate on Angular learning. You can learn "SystemJs
" in detail some time later using some other learning resources.
Later in the series, we will have one demo where we will make our project better by removing SystemJs and getting our work done with WebPack. As of now, simply continue with it.
Lab 4 – Interpolation
In this demo, we will explore an Angular feature called Interpolation.
As I said before, Angular Component is a combination of two things.
- Template – (also called as view) which represents the UI part of component.
- View class/component class – a custom class decorated with "
Component
" decorator. It encapsulates the UI data required and UI logic.
"Interpolation is a way to display dynamic data in component templates". It will be written using double-curly braces ({{...}}).
Let’s understand with demo.
Step 1 – Initialize Component Data
Open ‘app.component.ts’ file, create two variables in the AppComponent
class and simply assign a dummy values to in the "Constructor
".
import {Component} from "@angular/core"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
CompnayUrl:string;
CompanyName:string;
constructor(){
this.CompanyName="Train IT";
this.CompnayUrl="http://JustCompile.com";
}
}
Step 2 – Display Component Data
Now, change the template file "app.component.html" as follows:
<h1>Welcome to Learn Angular in 10 days series - Day 3</h1>
Company Name: <b>{{CompanyName}}</b>
<br>
Click <a href="{{CompanyUrl}}">here</a> to visit.
You can see two places where interpolation is used. One in between bold tags and second as a "href
" value.
Step 4 - Compile and Test the Output
Go to browser.
Very simple but useful example.
Lab 5 – Property Binding
Property binding means, binding a variable in component class to a property of some HTML element in the template. Such properties are called "Input properties".
Are you confused? Let’s do a very quick demo.
Step 1 – Implement Property Binding in AppComponent Template
Change the hyperlink in the "app.component.html" as follows:
<a [href]="CompanyUrl">here</a>
Have you noticed the difference? This time, there is no interpolation plus "href
" is wrapped between "[
" and "]
".
This is called "Property binding" – "CompanyUrl
" variable of AppComponent
class is bound to "href
" property of "anchor (a
)" element and "href
" is termed as "input property" in this example.
Step 2 - Compile and Test the Output
You will get the exact same output like before. It proves that interpolation and property binding does the same thing. But the truth is, property binding is more than just displaying value. Let’s understand with the demo.
Step 3 – Change Compnent Class
Add a new variable called "IsChecked
" of type Boolean in AppComponent
class.
...
export class AppComponent{
CompnayUrl:string;
CompanyName:string;
IsChecked:boolean;
constructor(){
this.CompanyName="Train IT";
this.CompnayUrl="http://www.JustCompile.com";
this.IsChecked=true;
}
}
Step 4 - Change Template
Create a checkbox control in template and use "IsChecked
" property with "checked
" attribute of HTML element.
<h1>Welcome to Learn Angular in 10 days series - Day 3</h1>
Company Name: <b>{{CompanyName}}</b>
<br>
Is Active: <input type="checkbox" checked={{IsChecked}}>
<br>
Click <a href="{{CompnayUrl}}">here</a> to visit.
Step 5 - Compile and Test the Output
Check the output in the browser.
As you can see, Checkbox
is checked.
Step 6 – Change IsChecked
In AppComponent
constructor, change "IsChecked
" to false
.
...
constructor(){
this.CompanyName="Train IT";
this.CompnayUrl="http://www.JustCompile.com";
this.IsChecked=false;
}
...
Step 7 - Compile and test the output
Check the output in the browser.
Checkbox
is still checked.
Step 8 – Implement Property Binding in Template
...
Is Active: <input type="checkbox" [checked]="IsChecked">
...
Step 9 - Compile and Test the Output
Check the output in the browser.
Wow! :) Checkbox
is unchecked now.
Step 10 – Change IsChecked
In AppComponent
constructor, change "IsChecked
" to true
.
...
constructor(){
this.CompanyName="Train IT";
this.CompnayUrl="http://www.JustCompile.com";
this.IsChecked=true;
}
...
Step 11 - Compile and Test the Output
Check the output in the browser.
Checkbox
is backed to checked state now.
Interpolation vs Property Binding
Interpolation call the "toString
" function of variable and then set the value. So value will always be string
where as in the case property binding datatype will be retained.
So, in simple terms – when variables are string
type, interpolation is a good option but for other datatypes property binding is preferred.
For string
values, interpolation is preferred because in interpolation concatenation is easier.
Check the below example:
<p>{{FirstName}} – {{LastName}}</p>
It will simply display "FirstName
" and "LastName
" concatenated along with hyphen (-).
Example – When FirstName
is "Sukesh
" and LastName
is "Marla
", it will display the following output:
Sukesh – Marla
Lab 6 – Working with Events in Angular
In this demo, we will see Event Binding (also known as Output properties) in action.
Step 1 – Change Template
Add a simple button in the ‘app.component.html’.
<h1>Welcome to Learn Angular in 10 days series - Day 3</h1>
Company Name: <b>{{CompanyName}}</b>
<br>
Is Active: <input type="checkbox" [checked]="IsChecked">
<br>
Click <a href="{{CompnayUrl}}">here</a> to visit.
<br>
<input type="button" value="ChangeValue" (click)="UpdateValue()">
In the above HTML, the "input
" tag has a special attribute called "click
" written between "(
" and ")
". It is the "output property". It is a way to handle events in Angular application.
Step 2 – Define Event handler
Open ‘app.component.ts’. Inside AppComponent
class, create a new method "UpdateValue
" as follows:
...
IsChecked:boolean;
constructor(){
this.CompanyName="Train IT";
this.CompnayUrl="http://www.JustCompile.com";
this.IsChecked=false;
}
UpdateValue():void{
this.CompanyName="Just Compile";
this.CompnayUrl="http://www.sukesh-Marla.com";
this.IsChecked=true;
}
}
Step 3 – Compile and Test the Output
Open the browser. You will get to see the following output.
When "ChangeValue
" button is clicked, "UpadateValue
" function in the component class got invoked. This is called event binding and "click
" is the output property in the example.
After button click, the entire UI gets re-rendered with new values. It happens, because Angular has something called Change Detection. Change Detection is a mechanism which keeps the UI in sync with the data. Every time data get changed, UI get re-rendered. We will have more detailed discussion on Change Detection later in the series.
Lab 7 – Working with Complex Objects
In the next lab, we will understand how to deal with Complex Objects in Angular.
Step 1 – Create Model
In the programming world, Model represents the data. Let’s use the same terminology in our project. Create a new folder called "Models" in the "AppModule" folder.
Then, create a new TypeScript file "Employee.ts" inside "Models" folder as follows:
export class Employee{
FName:string;
LName:string;
Salary:number;
}
Step 2 – Use Model in Component Class
It’s time to redefine AppComponent
Class.
Remove all the existing code from AppComponent
and then create a new global variable of type Employee
and initialize it with dummy values. Here is the complete code.
import {Component} from "@angular/core"
import {Employee} from "../Models/Employee"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
emp:Employee;
constructor(){
this.emp=new Employee();
this.emp.FName="Sukesh";
this.emp.LName="Marla";
this.emp.Salary=10000;
}
}
Step 3 – Display Model Data in Template
Finally, let’s redefine our template file "app.component.html". It can be done easily with the help of interpolation. Here is the code.
<h1>Welcome to Learn Angular in 10 days series - Day 3</h1>
Employee Name: {{emp.FName}} {{emp.LName}}
<br>
Salary: {{emp.Salary}}
Step 3 – Compile and Test the Output
Open the browser. You will get to see following output:
Simple example.
Understand the Project
As I promised on Day 1, we will create one simple Angular Project at the end of the day. It’s time to start with it.
We will create our project step by step. Sometimes, we will create something which is not good from a best practice point of view. But that’s fine, we will do it, discuss the issues in it and then get into the best practice.
When it comes to learning, "We should learn both best and bad practices of a technology".
Let’s start with the understanding what we are going to develop.
Above one is Employee
UI. We will have some similar UI for Customer
, Product
, Customer
and Supplier
.
Let’s start developing it step by step.
Lab 8 – Working with Collections
Let’s start with displaying multiple Employees
in a single UI.
In order to do it, we have to use one very interesting feature of Angular that is "Attribute Directives".
Step 1 – Prepare the Component Class
Open "app.component.ts" file. Remove all the existing code from AppComponent
and then create a new global variable of type Array<Employee>
and initialize it with dummy values. Here is the complete code.
import {Component} from "@angular/core"
import {Employee} from "../Models/Employee"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
Employees:Array<Employee>;
constructor(){
this.Employees =new Array<Employee>();
let e1=new Employee();;
e1.FName="Sukesh";
e1.LName="Marla";
e1.Salary=10000;
this.Employees.push(e1);
let e2=new Employee();;
e2.FName="Gabbar";
e2.LName="Singh";
e2.Salary=20000;
this.Employees.push(e2);
let e3=new Employee();;
e3.FName="Dragon";
e3.LName="Hunter";
e3.Salary=30000;
this.Employees.push(e3);
}
}
Step 2 – Redefine the Template
Now for displaying multiple Employees
, we have to use HTML "table
" tag. Challenge will be, creating "tr
" tag because it has to be created dynamically. For every single Employee
in the list one "tr
" should be created.
As a best practice, every DOM manipulation in Angular project must happen without accessing DOM directly in component class. We will explore various ways to achieve it throughout the series.
For our current requirement, we will use an Angular Directive called "*ngFor
".
"Directives change the default behavior of HTML elements when attached."
For instance "*ngFor
" directive repeats the host element based on expression provided.
Open "app.component.html", remove existing contents and put the following contents in it.
<h1>Employee</h1>
<table border="1" >
<tr>
<th>Emp Name</th>
<th>Salary </th>
</tr>
<tr *ngFor="let emp of Employees">
<td>{{emp.FName}} {{emp.LName}}</td>
<td>{{emp.Salary}}</td>
</tr>
</table>
Check the second "tr
" in the above table. You will notice "*ngFor
" used with it.
Let’s examine the expression provided in this example, it is "let emp of Employees
".
Angular iterate through "Employees
", which is an array of "Employee
" and then create one row ("tr
") for each item in the list. "emp
" will be set to individual Employee
item in the current iteration.
Step 3 – Compile and Test the Output
Open the browser. You will get to see following output:
Later in the series, we will display a real time data instead of hard coded one.
Lab 9 - Data Entry Screen
In this lab, we will concentrate on Data Entry section of our project.
Step 1 – Create Data Entry Section
Open ‘app.component.html’ and append the following HTML to it.
<br>
<div>
FName: <input type="text"><br>
LName: <input type="text"><br>
Salary: <input type="text"><br>
<input type="button" value="Save" (click)="SaveEmployee()">
</div>
Note: Please make sure that you have appended the above HTML to the existing HTML. (Don’t replace it.)
Step 2 – Define SaveEmployee
Open app.component.ts and define SaveEmployee
method as follows:
SaveEmployee():void{
let e1=new Employee();
e1.FName="F1";
e1.LName="L1";
e1.Salary=40000;
this.Employees.push(e1);
}
Step 3 – Compile and Test the Output
Open the browser. You will get to see the following output.
As you can see, we just have to add a new item to the collection and UI automatically got re-rendered. It's because of "Change Detection".
We have a very detailed lab on input controls where we will talk about various ways of getting input values in component class. Current example is inserting hard coded employees, let’s stick to that.
Lab 10 – Conditional Rendering
Current UI has both Employee
list and data entry screen visible at the same time but according to our requirement, only one thing should be visible at a time.
In this demo, we will implement conditional rendering in our project.
Let’s start implementing the same.
Plan the Logic
To achieve our current requirement (conditional rendering), we will perform the following steps.
In component class, we will make the following changes:
- Create a Boolean variable "
IsAddNew
" which will represent the current condition in the UI. - Create "
ShowAddNew
" function which will set "IsAddNew
" to true
- Create "
HideAddNew
" function which will set "IsAddNew
" to false
- In the existing "
SaveEmployee
" function, set "IsAddNew
" to false
In the template side, we will use "hidden
" attribute of HTML element combined with Property binding in Angular.
Let’s do in reality and understand it better.
Step 1 – Redesign the Template
Let’s start with redesigning AppComponent
template that is "app.component.html". We need two more buttons, "Add New" and "Cancel".
Here is the complete HTML.
<h1>Employee</h1>
<div [hidden]="IsAddNew">
<input type="button" value="Add New" (click)="ShowAddNew()">
<table border="1">
<tr>
<th>Emp Name</th>
<th>Salary </th>
</tr>
<tr *ngFor="let emp of Employees">
<td>{{emp.FName}} {{emp.LName}}</td>
<td>{{emp.Salary}}</td>
</tr>
</table>
</div>
<div [hidden]="!IsAddNew">
FName: <input type="text"><br>
LName: <input type="text"><br>
Salary: <input type="text"><br>
<input type="button" value="Save" (click)="SaveEmployee()">
<input type="button" value="Cancel" (click)="HideAddNew()">
</div>
You can notice that "IsAddNew
" variable is bound to "hidden
" attribute via property binding.
Don’t miss the "!
" symbol used with "IsAddNew
" in second div
. It means "hidden
" will be bound to reverse value of "IsAddNew
". In simple words, Second "div
" will get hidden/invisible when "IsAddNew
" is not true
. If "IsAddNew
" is true
, it will be displayed.
Step 2 – Implement Logic in Component Class
Implement the following changes in "app.component.ts" file.
...
…
export class AppComponent{
Employees:Array<Employee>;
IsAddNew:boolean;
constructor(){
this.IsAddNew=false;
this.Employees =new Array<Employee>();
...
...
}
SaveEmployee():void{
...
...
this.IsAddNew=false;
}
ShowAddNew():void{
this.IsAddNew=true;
}
HideAddNew():void{
this.IsAddNew=false;
}
}
Step 3 –Compile and Test the Output
Open the browser. You will get to see the following output:
Summary
Here, we are done with our Day 3.
Currently, our application is nothing but a big UI. We have one component and that’s it. Definitely, we are not following Component oriented style. Next time, we will break our application into multiple small, reusable, meaningful and composable web components.
On day 4, we will also learn how to create custom Input/output properties and how to deal with input controls in Angular. Till then, happy coding and stay tuned.
History
- 9th August, 2017: Initial version