Angular8 Tutorial
Angular8 Tutorial
i
Angular 8
Audience
This tutorial is prepared for professionals who are aspiring to make a career in the field of
Web application developer. This tutorial is intended to make you comfortable in getting
started with the Angular8 concepts with examples.
Prerequisites
Before proceeding with the various types of concepts given in this tutorial, we assume that
the readers have the basic knowledge on HTML, CSS and OOPS concepts. In addition to
this, it will be very helpful, if the readers have a sound knowledge on TypeScript and
JavaScript.
All the content and graphics published in this e-book are the property of Tutorials Point (I)
Pvt. Ltd. The user of this e-book is prohibited to reuse, retain, copy, distribute or republish
any contents or a part of contents of this e-book in any manner without written consent
of the publisher.
We strive to update the contents of our website and tutorials as timely and as precisely as
possible, however, the contents may contain inaccuracies or errors. Tutorials Point (I) Pvt.
Ltd. provides no guarantee regarding the accuracy, timeliness or completeness of our
website or its contents including this tutorial. If you discover any errors on our website or
in this tutorial, please notify us at contact@tutorialspoint.com
ii
Angular 8
Table of Contents
Table of Contents ............................................................................................................................................. i
Applications ..................................................................................................................................................... 2
Angular 8 installation....................................................................................................................................... 3
Component ...................................................................................................................................................... 9
Template........................................................................................................................................................ 10
Modules ......................................................................................................................................................... 11
Services .......................................................................................................................................................... 13
Templates ...................................................................................................................................................... 17
i
Angular 8
Observable..................................................................................................................................................... 62
Operations ..................................................................................................................................................... 64
iv
1. Angular 8 ― Introduction Angular 8
Angular 8 is a TypeScript based full-stack web framework for building web and mobile
applications. One of the major advantage is that the Angular 8 support for web application
that can fit in any screen resolution. Angular application is fully compatible for mobiles,
tablets, laptops or desktops. Angular 8 has an excellent user interface library for web
developers which contains reusable UI components.
This functionality helps us to create Single Page Applications (SPA). SPA is reactive and
fast application. For example, if you have a button in single page and click on the button
then the action performs dynamically in the current page without loading the new page
from the server. Angular 8 is Typescript based object oriented programming and support
features for server side programming as well.
AngularJS
AngularJs is very powerful JavaScript framework. It was released in October 2010.
AngularJS based on Model View Controller (MVC) architecture and automatically handles
JavaScript code suitable for each browser.
Angular 2.0
Angular 2.0 was released in September 2016. It is re-engineered and rewritten version of
AngularJS. AngularJs had a focus on controllers but, version 2 has changed focus on
components. Components are the main building block of application. It supports features
for speed in rendering, updating pages and building cross-platform native mobile apps for
Google Android and iOS.
Angular 4.0
Angular 4.0 was released in March 2017. It is updated to TypeScript 2.2, supports ng if-
else conditions whereas Angular 2 supported only if conditions. Angular 4.0 introduces
animation packages, Http search parameters and finally angular 4 applications are smaller
and faster.
Angular 5.0
Angular 5.0 was released in November 2017. It supported some of the salient features
such as HTTPClient API, Lambda support, Improved Compiler and build optimizer.
Angular 6.0
1
Angular 8
Angular 6.0 was released in May 2018. Features added to this version are updated Angular
CLI, updated CDK, updated Angular Material, multiple validators and usage of reactive JS
library.
Angular 7.0
Angular 7.0 was released in October 2018. Some of salient features are Google supported
community, POJO based development, modular structure, declarative user interface and
modular structure.
Bazel support - If your application uses several modules and libraries, Bazel
concurrent builds helps to load faster in your application.
Lazy loading - Angular 8 splits AppRoutingModule into smaller bundles and
loads the data in the DOM.
Differential loading - When you create an application, Angular CLI generates
modules and this will be loaded automatically then browser will render the data.
Web worker - It is running in the background, without affecting the performance
of a page.
Improvement of CLI workflow - Angular 8 CLI commands ng-build, ng-test
and ng-run are extended to third party libraries.
Router Backward Compatibility - Angular router backward compatibility feature
helps to create path for larger projects so user can easily add their coding with the
help of lazy coding.
Opt-in usage sharing - User can opt into share Angular CLI usage data.
Applications
Some of the popular website using Angular Framework are listed below:
2
2. Angular 8 — Installation Angular 8
This chapter explains about how to install Angular 8 on your machine. Before moving to
the installation, let’s verify the prerequisite first.
Prerequisite
As we know already, Angular is written in TypeScript. We need Node and npm to compile
the files into JavaScript after that, we can deploy our application. For this purpose,
Node.js must be installed in your system. Hopefully, you have installed Node.js on your
machine.
node --version
v14.2.0
If Node is not installed, you can download and install by visiting the following link:
https://nodejs.org/en/download/.
Angular 8 installation
Angular 8 CLI installation is based on very simple steps. It will take not more than five
minutes to install.
npm is used to install Angular 8 CLI. Once Node.js is installed, npm is also installed. If
you want verify it, type the below command:
npm -v
6.14.4
To verify Angular 8 is properly installed on your machine, type the below command:
ng version
3
Angular 8
Node: 14.2.0
Package Version
------------------------------------------------------
@angular-devkit/architect 0.803.26
@angular-devkit/core 8.3.26
@angular-devkit/schematics 8.3.26
@schematics/angular 8.3.26
@schematics/update 0.803.26
rxjs 6.4.0
4
3. Angular 8 — Creating First Application Angular 8
Let us create a simple angular application and analyse the structure of the basic angular
application.
Let us check whether the Angular Framework is installed in our system and the version of
the installed Angular version using below command:
ng --version
Here,
ng is the CLI application used to create, manage and run Angular Application. It written
in JavaScript and runs in NodeJS environment.
The result will show the details of the Angular version as specified below:
Package Version
------------------------------------------------------
@angular-devkit/architect 0.803.26
@angular-devkit/core 8.3.26
@angular-devkit/schematics 8.3.26
@schematics/angular 8.3.26
@schematics/update 0.803.26
rxjs 6.4.0
Let us create an Angular application to check our day to day expenses. Let us give
ExpenseManager as our choice for our new application. Use below command to create
the new application.
cd /path/to/workspace
ng new expense-manager
Here,
new is one of the command of the ng CLI application. It will be used to create new
application. It will ask some basic question in order to create new application. It is enough
to let the application choose the default choices. Regarding routing question as mentioned
below, specify No. We will see how to create routing later in the Routing chapter.
5
Angular 8
Once the basic questions are answered, the ng CLI application create a new Angular
application under expense-manager folder.
cd expense-manager
Let us check the partial structure of the application. The structure of the application is as
follows:
| favicon.ico
| index.html
| main.ts
| polyfills.ts
| styles.css
|
+---app
| app.component.css
| app.component.html
| app.component.spec.ts
| app.component.ts
| app.module.ts
|
+---assets
| .gitkeep
|
+---environments
environment.prod.ts
environment.ts
Here,
We have shown, only the most important file and folder of the application.
favicon.ico and assets are application’s icon and application’s root asset folder.
polyfills.ts contains standard code useful for browser compatibility.
environments folder will have the application’s setting. It includes production and
development setup.
main.ts file contains the startup code.
index.html is the application base HTML code.
styles.css is the base CSS code.
app folder contains the Angular application code, which will be learn elaborately
in the upcoming chapters.
ng serve
10% building 3/3 modules 0 activei wds: Project is running at
http://localhost:4200/webpack-dev-server/
6
Angular 8
Here, serve is the sub command used to compile and run the Angular application using
a local development web server. ng server will start a development web server and
serves the application under port, 4200.
Let us fire up a browser and opens http://localhost:4200. The browser will show the
application as shown below:
Let us change the title of the application to better reflect our application. Open
src/app/app.component.ts and change the code as specified below:
7
Angular 8
We will change the application and learn how to code an Angular application in the
upcoming chapters.
8
4. Angular 8 — Architecture Angular 8
Angular framework is based on four core concepts and they are as follows:
Components.
Templates with Data binding and Directives.
Modules.
Services and dependency injection.
Component
The core of the Angular framework architecture is Angular Component. Angular
Component is the building block of every Angular application. Every angular application is
made up of one more Angular Component. It is basically a plain JavaScript / Typescript
class along with a HTML template and an associated name.
The HTML template can access the data from its corresponding JavaScript / Typescript
class. Component’s HTML template may include other component using its selector’s value
(name). The Angular Component may have an optional CSS Styles associated it and the
HTML template may access the CSS Styles as well.
// src/app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Expense Manager';
}
9
Angular 8
app-root is the selector / name of the component and it is specified using selector meta
data of the component’s decorator. app-root can be used by application root document,
src/index.html as specified below:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ExpenseManager</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
app.component.css is the CSS style document associated with the component. The
component style is specified using styleUrls meta data of the @Component decorator.
AppComponent property (title) can be used in the HTML template as mentioned below:
{{ title }}
Template
Template is basically a super set of HTML. Template includes all the features of HTML and
provides additional functionality to bind the component data into the HTML and to
dynamically generate HTML DOM elements.
The core concept of the template can be categorised into two items and they are as follows:
Data binding
{{ title }}
Directives
Used to include logic as well as enable creation of complex HTML DOM elements.
<p *ngIf="canShow">
10
Angular 8
This sectiom will be shown only when the *canShow* propery's value in
the corresponding component is *true*
</p>
<p [showToolTip]='tips' />
Here, ngIf and showToolTip (just an example) are directives. ngIf create the paragraph
DOM element only when canShow is true. Similarly, showToolTip is Attribute
Directives, which adds the tooltip functionality to the paragraph element.
When user mouse over the paragraph, a tooltip with be shown. The content of the tooltip
comes from tips property of its corresponding component.
Modules
Angular Module is basically a collection of related features / functionality. Angular
Module groups multiple components and services under a single context.
For example, animations related functionality can be grouped into single module and
Angular already provides a module for the animation related functionality,
BrowserAnimationModule module.
An Angular application can have any number of modules but only one module can be set
as root module, which will bootstrap the application and then call other modules as and
when necessary. A module can be configured to access functionality from other module as
well. In short, components from any modules can access component and services from
any other modules.
Following diagram depicts the interaction between modules and its components.
11
Angular 8
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Here,
NgModule decorator is used to convert a plain Typescript / JavaScript class into
Angular module.
12
Angular 8
The following diagram depicts the relationship between Module, Component and Services.
Services
Services are plain Typescript / JavaScript class providing a very specific functionality.
Services will do a single task and do it best. The main purpose of the service is reusability.
Instead of writing a functionality inside a component, separating it into a service will make
it useable in other component as well.
Also, Services enables the developer to organise the business logic of the application.
Basically, component uses services to do its own job. Dependency Injection is used to
properly initialise the service in the component so that the component can access the
services as and when necessary without any setup.
src/main.ts bootstraps the AppModule (src/app.module.ts), which is the root module for
every Angular application.
13
Angular 8
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Here,
AppModule also loads all the registered service using Dependency Injection (DI)
framework.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ExpenseManager</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-
scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
@NgModule({
declarations: [
AppComponent
AnyOtherComponent
14
Angular 8
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Component use other component through directive in its template using target
component’s selector name.
<component-selector-name></component-selector-name>
Also, all registered services are accessible to all Angular components through
Dependency Injection (DI) framework.
15
5. Angular 8 — Angular Components and Angular 8
Templates
As we learned earlier, Components are building block of Angular application. The main
job of Angular Component is to generate a section of web page called view. Every
component will have an associated template and it will be used to generate views.
Let us learn the basic concept of component and template in this chapter.
Add a component
Let us create a new component in our ExpenseManager application.
cd /go/to/expense-manager
Output
Here,
@Component({
selector: 'app-expense-entry',
templateUrl: './expense-entry.component.html',
styleUrls: ['./expense-entry.component.css']
})
export class ExpenseEntryComponent implements OnInit {
16
Angular 8
title: string;
constructor() { }
ngOnInit() {
this.title = "Expense Entry"
}
}
Here,
app-expense-entry is the selector value and it can be used as regular HTML Tag.
We will update the content of the component during the course of learning more about
templates.
Templates
The integral part of Angular component is Template. It is used to generate the HTML
content. Templates are plain HTML with additional functionality.
Attach a template
17
Angular 8
templateUrl
We already know how to use templateUrl. It expects the relative path of the template file.
For example, AppComponent set its template as app.component.html.
templateUrl: './app.component.html',
template
template enables to place the HTML string inside the component itself. If the template
content is minimal, then it will be easy to have it Component class itself for easy tracking
and maintenance purpose.
@Component({
selector: 'app-root',
templateUrl: `<h1>{{ title }}</h1>`,
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'Expense Manager';
ngOnInit() {
this.debugService.info("Angular Application starts");
}
}
Attach Stylesheet
Angular Templates can use CSS styles similar to HTML. Template gets its style information
from two sources, a) from its component b) from application configuration.
Component configuration
Component decorator provides two option, styles and styleUrls to provide CSS style
information to its template.
Styles: styles option is used to place the CSS inside the component itself.
styleUrls: styleUrls is used to refer external CSS stylesheet. We can use multiple
stylesheet as well.
Application configuration
18
Angular 8
"projects": {
"expense-manager": {
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/expense-manager",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
},
},
}
}},
"defaultProject": "expense-manager"
}
Here,
styles option sets src/styles.css as global CSS stylesheet. We can include any number
of CSS stylesheets as it supports multiple values.
Include bootstrap
Let us include bootstrap into our ExpenseManager application using styles option and
change the default template to use bootstrap components.
cd /go/to/expense-manager
Here,
We have installed JQuery, because, bootstrap uses jquery extensively for advanced
components.
19
Angular 8
{
"projects": {
"expense-manager": {
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/expense-manager",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"./node_modules/bootstrap/dist/css/bootstrap.css",
"src/styles.css"
],
"scripts": [
"./node_modules/jquery/dist/jquery.js",
"./node_modules/bootstrap/dist/js/bootstrap.js"
]
},
},
}
}},
"defaultProject": "expense-manager"
}
Here,
scripts option is used to include JavaScript library. JavaScript registered through scripts
will be available to all Angular components in the application.
<span class="sr-only">(current)</span>
20
Angular 8
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Report</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Add Expense</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
</ul>
</div>
</div>
</nav>
<app-expense-entry></app-expense-entry>
Here,
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
21
Angular 8
<strong><em>Amount:</em></strong>
</div>
<div class="col" style="text-align: left;">
20
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Category:</em></strong>
</div>
<div class="col" style="text-align: left;">
Food
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Location:</em></strong>
</div>
<div class="col" style="text-align: left;">
Zomato
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Spend On:</em></strong>
</div>
<div class="col" style="text-align: left;">
June 20, 2020
</div>
</div>
</div>
</div>
</div>
</div>
22
Angular 8
We will improve the application to handle dynamic expense entry in next chapter.
23
6. Angular 8 — Data Binding Angular 8
Data binding deals with how to bind your data from component to HTML DOM elements
(Templates). We can easily interact with application without worrying about how to insert
your data. We can make connections in two different ways one way and two-way binding.
Open command prompt and create new Angular application using below command:
cd /go/to/workspace
ng new databind-app
cd databind-app
ng serve
String interpolation
In general, String interpolation is the process of formatting or manipulating strings. In
Angular, Interpolation is used to display data from component to view (DOM). It is
denoted by the expression of {{ }} and also known as mustache syntax.
Let’s create a simple string property in component and bind the data to view.
24
Angular 8
<h1>{{appName}}</h1>
Add the test component in your app.component.html file by replacing the existing
content as follows:
<app-test></app-test>
Finally, start your application (if not done already) using the below command:
ng serve
Event binding
Events are actions like mouse click, double click, hover or any keyboard and mouse
actions. If a user interacts with an application and performs some actions, then event will
be raised. It is denoted by either parenthesis () or on-. We have different ways to bind
an event to DOM element. Let’s understand one by one in brief.
showData($event: any){
console.log("button is clicked!");
if($event) {
console.log($event.target);
console.log($event.target.value);
}
}
}
25
Angular 8
<h2>Event Binding</h2>
Alternatively, you can use prefix - on using canonical form as shown below:
Finally, start your application (if not done already) using the below command:
ng serve
Now, run your application and you could see the below response:
Here, when the user clicks on the button, event binding understands to button click action
and call component showData() method so we can conclude it is one-way binding.
Property binding
Property binding is used to bind the data from property of a component to DOM
elements. It is denoted by [].
26
Angular 8
Here,
Finally, start your application (if not done already) using the below command:
ng serve
Attribute binding
Attribute binding is used to bind the data from component to HTML attributes. The
syntax is as follows:
For example,
Here,
Finally, start your application (if not done already) using the below command:
ng serve
Class binding
Class binding is used to bind the data from component to HTML class property. The
syntax is as follows:
Class Binding provides additional functionality. If the component data is boolean, then
the class will bind only when it is true. Multiple class can be provided by string (“foo bar”)
as well as Array of string. Many more options are available.
For example,
28
Angular 8
<p [class]="myClasses">
.red {
color: red;
}
.blue {
color: blue;
}
Finally, start your application (if not done already) using the below command:
ng serve
29
Angular 8
Style binding
Style binding is used to bind the data from component into HTML style property. The
syntax is as follows:
For example,
myColor = 'brown';
Finally, start your application (if not done already) using the below command:
ng serve
30
Angular 8
NgModel
NgModel is a standalone directive. ngModel directive binds form control to property and
property to form control. The syntax of ngModel is as follows:
For example,
@NgModule({
imports: [
BrowserModule,
FormsModule
]
})
export class AppModule { }
Here,
Property is bind to form control ngModel directive and if you enter any text in the textbox,
it will bind to the property. After running your application, you could see the below
changes:
Finally, start your application (if not done already) using the below command:
ng serve
Now, run your application and you could see the below response:
31
Angular 8
Now, try to change the input value to Jack. As you type, the text below the input gets
changed and the final output will be as shown below:
Working example
32
Angular 8
Let us implement all the concept learned in this chapter in our ExpenseManager
application.
cd /go/to/expense-manager
ngOnInit() {
this.title = "Expense Entry";
this.expenseEntry = {
id: 1,
item: "Pizza",
amount: 21,
category: "Food",
location: "Zomato",
spendOn: new Date(2020, 6, 1, 10, 10, 10),
createdOn: new Date(2020, 6, 1, 10, 10, 10),
};
}
}
33
Angular 8
<div class="row">
<div class="col-lg-12 text-center" style="padding-top: 20px;">
<div class="container" style="padding-left: 0px; padding-right:
0px;">
<div class="row">
<div class="col-sm" style="text-align: left;">
{{ title }}
</div>
<div class="col-sm" style="text-align: right;">
<button type="button" class="btn btn-
primary">Edit</button>
</div>
</div>
</div>
<div class="container box" style="margin-top: 10px;">
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Item:</em></strong>
</div>
<div class="col" style="text-align: left;">
{{ expenseEntry.item }}
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Amount:</em></strong>
</div>
<div class="col" style="text-align: left;">
{{ expenseEntry.amount }}
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Category:</em></strong>
</div>
<div class="col" style="text-align: left;">
{{ expenseEntry.category }}
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Location:</em></strong>
</div>
<div class="col" style="text-align: left;">
{{ expenseEntry.location }}
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Spend On:</em></strong>
34
Angular 8
</div>
<div class="col" style="text-align: left;">
{{ expenseEntry.spendOn }}
</div>
</div>
</div>
</div>
</div>
</div>
35
7. Angular 8 — Directives Angular 8
Angular 8 directives are DOM elements to interact with your application. Generally,
directive is a TypeScript function. When this function executes Angular compiler checked
it inside DOM element. Angular directives begin with ng- where ng stands for Angular and
extends HTML tags with @directive decorator.
Directives enables logic to be included in the Angular templates. Angular directives can be
classified into three categories and they are as follows:
Attribute directives
Used to add new attributes for the existing HTML elements to change its look and
behaviour.
For example,
Here, showToolTip refers an example directive, which when used in a HTML element
will show tips while user hovers the HTML element.
Structural directives
For example,
<div *ngIf="isNeeded">
Only render if the *isNeeded* value has true value.
</div>
Here, ngIf is a built-in directive used to add or remove the HTML element in the current
HTML document. Angular provides many built-in directive and we will learn in later
chapters.
Component can be used as directives. Every component has Input and Output option
to pass between component and its parent HTML elements.
For example,
36
Angular 8
Here, list-item is a component and items is the input option. We will learn how to create
component and advanced usages in the later chapters.
Before moving to this topic, let’s create a sample application (directive-app) in Angular
8 to work out the learnings.
Open command prompt and create new Angular application using below command:
cd /go/to/workspace
ng new directive-app
cd directive-app
ng serve
DOM Overview
Let us have a look at DOM model in brief. DOM is used to define a standard for accessing
documents. Generally, HTML DOM model is constructed as a tree of objects. It is a
standard object model to access html elements.
Structural directives
Structural directives change the structure of DOM by adding or removing elements. It is
denoted by * sign with three pre-defined directives NgIf, NgFor and NgSwitch. Let’s
understand one by one in brief.
NgIf directive
NgIf directive is used to display or hide data in your application based on the condition
becomes true or false. We can add this to any tag in your template.
<p>test works!</p>
<div *ngIf="true">Display data</div>
<app-test></app-test>
Start your server (if not started already) using the below command:
ng serve
Now, run your application and you could see the below response:
ngIfElse directive
ngIfElse is similar to ngIf except, it provides option to render content during failure
scenario as well.
<p>ngIfElse example!</p>
<div *ngIf="isLogIn; else isLogOut">
Hello you are logged in
</div>
38
Angular 8
<ng-template #isLogOut>
You're logged out..
</ng-template>
Finally, start your application (if not done already) using the below command:
ng serve
Now, run your application and you could see the below response:
Here, isLogOut value is assigned as true, so it goes to else block and renders ng-
template. We will learn ng-template later in this chapter.
ngFor directive
ngFor is used to repeat a portion of elements from the list of items.
list = [1,2,3,4,5];
<h2>ngFor directive</h2>
<ul>
<li *ngFor="let l of list">
{{l}}
</li>
</ul>
Here, the let keyword creates a local variable and it can be referenced anywhere in your
template. The let l creates a template local variable to get the list elements.
Finally, start your application (if not done already) using the below command:
39
Angular 8
ng serve
Now, run your application and you could see the below response:
trackBy
Sometimes, ngFor performance is low with large lists. For example, when adding new
item or remove any item in the list may trigger several DOM manipulations. To iterate
over large objects collection, we use trackBy.
Let’s understand how trackBy works along with ngFor by doing a sample.
"name": "student2"
},
{
"id": 3,
"name": "student3"
},
40
Angular 8
{
"id": 4,
"name": "student4"
}
];
Here,
We have created, trackByData() method to access each student element in a unique way
based on the id.
Add the below code in test.component.html file to define trackBy method inside ngFor.
<ul>
<li *ngFor="let std of studentArr; trackBy: trackByData">
{{std.name}}
</li>
</ul>
Finally, start your application (if not done already) using the below command:
ng serve
Now, run your application and you could see the below response:
Here, the application will print the student names. Now, the application is tracking student
objects using the student id instead of object references. So, DOM elements are not
affected.
NgSwitch directive
NgSWitch is used to check multiple conditions and keep the DOM structure as simple and
easy to understand.
41
Angular 8
<h2>ngSwitch directive</h2>
<ul [ngSwitch]="logInName">
<li *ngSwitchCase="'user'">
<p>User is logged in..</p>
</li>
<li *ngSwitchCase="'admin'">
<p>admin is logged in</p>
</li>
<li *ngSwitchDefault>
<p>Please choose login name</p>
</li>
</ul>
Finally, start your application (if not done already) using the below command:
ng serve
Now, run your application and you could see the below response:
Here, we have defined logInName as admin. So, it matches second SwitchCase and
prints above admin related message.
Attribute directives
Attribute directives performs the appearance or behavior of DOM elements or components.
Some of the examples are NgStyle, NgClass and NgModel. Whereas, NgModel is two-way
attribute data binding explained in previous chapter.
ngStyle
42
Angular 8
ngStyle directive is used to add dynamic styles. Below example is used to apply blue color
to the paragraph.
Start your application (if not done already) using the below command:
ng serve
Now, run your application and you could see the below response:
ngClass
ngClass is used to add or remove CSS classes in HTML elements.
ng g class User
Here, we have created two property userId and userName in the User class.
Here, we have declared a local variable, users and initialise with 2 users object.
.highlight
{
color: red;
}
<div class="container">
<br/>
<div *ngFor="let user of users" [ngClass]="{
'highlight':user.userName === 'User1'
}">
{{ user.userName }}
</div>
</div>
Here,
Finally, start your application (if not done already) using the below command:
ng serve
Now, run your application and you could see the below response:
44
Angular 8
Custom directives
Angular provides option to extend the angular directive with user defined directives and it
is called Custom directives. Let us learn how to create custom directive in this chapter.
After executing this command, you could see the below response:
@NgModule({
declarations: [
AppComponent,
TestComponent,
CustomstyleDirective
]
})
@Directive({
selector: '[appCustomstyle]'
})
export class CustomstyleDirective {
45
Angular 8
constructor(el: ElementRef) {
el.nativeElement.style.fontSize = '24px';
}
}
Here, constructor method gets the element using CustomStyleDirective as el. Then,
it accesses el’s style and set its font size as 24px using CSS property.
Finally, start your application (if not done already) using the below command:
ng serve
Now, run your application and you could see the below response:
ng-template
ng-template is used to create dynamic and reusable templates. It is a virtual element. If
you compile your code with ng-template then is converted as comment in DOM.
For example,
<h3>ng-template</h3>
If you run the application, then it will print only h3 element. Check your page source,
template is displayed in comment section because it is a virtual element so it does not
render anything. We need to use ng-template along with Angular directives.
Normally, directive emits the HTML tag it is associated. Sometimes, we don’t want the tag
but only the content. For example, in the below example, li will be emitted.
46
Angular 8
<ng-template [ngIf]=true>
<div><h2>ng-template works!</h2></div>
</ng-template>
Here, if ngIf condition becomes true, it will print the data inside div element. Similarly,
you can use ngFor and ngSwitch directives as well.
NgForOf directive
ngForOf is also a structural directive used to render an item in a collection. Below example
is used to show ngForOf directive inside ng-template.
@Component({
selector: 'app-test',
template: `
<div>
<ng-template ngFor let-item [ngForOf]="Fruits" let-i="index">
<p>{{i}}</p>
</ng-template>
</div>`
,
styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
Fruits = ["mango","apple","orange","grapes"];
ngOnInit()
{
}
}
If you run the application, it will show the index of each elements as shown below:
0
1
2
3
Component directives
Component directives are based on component. Actually, each component can be used as
directive. Component provides @Input and @Output decorator to send and receive
information between parent and child components.
<p>child works!</p>
<p>Hi {{ userName }}</p>
<h1>Test component</h1>
<app-child [userName]="name"><app-child>
Finally, start your application (if not done already) using the below command:
ng serve
Now, run your application and you could see the below response:
[](images/directive-app/component_as_directive.PNG"
Working example
Let us add a new component in our ExpenseManager application to list the expense
entries.
cd /go/to/expense-manager
48
Angular 8
ng serve
Output
Here, the command creates the ExpenseEntryList Component and update the necessary
code in AppModule.
getExpenseEntries() : ExpenseEntry[] {
let mockExpenseEntries : ExpenseEntry[] = [
{ id: 1,
item: "Pizza",
amount: Math.floor((Math.random() * 10) + 1),
category: "Food",
location: "Mcdonald",
spendOn: new Date(2020, 4, Math.floor((Math.random() *
30) + 1), 10, 10, 10),
createdOn: new Date(2020, 4, Math.floor((Math.random()
* 30) + 1), 10, 10, 10) },
{ id: 1,
item: "Pizza",
amount: Math.floor((Math.random() * 10) + 1),
category: "Food",
location: "KFC",
spendOn: new Date(2020, 4, Math.floor((Math.random() *
30) + 1), 10, 10, 10),
createdOn: new Date(2020, 4, Math.floor((Math.random()
* 30) + 1), 10, 10, 10) },
{ id: 1,
49
Angular 8
item: "Pizza",
{ id: 1,
item: "Pizza",
amount: Math.floor((Math.random() * 10) + 1),
category: "Food",
location: "KFC",
spendOn: new Date(2020, 4, Math.floor((Math.random() *
30) + 1), 10, 10, 10),
createdOn: new Date(2020, 4, Math.floor((Math.random()
* 30) + 1), 10, 10, 10) },
{ id: 1,
item: "Pizza",
amount: Math.floor((Math.random() * 10) + 1),
category: "Food",
location: "KFC",
spendOn: new Date(2020, 4, Math.floor((Math.random() *
30) + 1), 10, 10, 10),
createdOn: new Date(2020, 4, Math.floor((Math.random()
* 30) + 1), 10, 10, 10) },
];
return mockExpenseEntries;
}
Declare a local variable, expenseEntries and load the mock list of expense entries as
mentioned below:
title: string;
expenseEntries: ExpenseEntry[];
constructor() { }
ngOnInit() {
this.title = "Expense Entry List";
this.expenseEntries = this.getExpenseEntries();
}
50
Angular 8
<div class="container">
<div class="row">
<div class="col-lg-12 text-center" style="padding-top: 20px;">
Here,
Used bootstrap table. table and table-striped will style the table according to
Boostrap style standard.
Used ngFor to loop over the expenseEntries and generate table rows.
...
<app-expense-entry-list></app-expense-entry-list>
52
8. Angular 8 — Pipes Angular 8
Pipes are referred as filters. It helps to transform data and manage data within
interpolation, denoted by {{ | }}. It accepts data, arrays, integers and strings as inputs
which are separated by ‘|’ symbol. This chapter explains about pipes in detail.
Adding parameters
Create a date method in your test.component.ts file.
<div>
Today's date :- {{presentDate}}
</div>
Here,
<div>
Today's date :- {{presentDate | date }}
</div>
Parameters in Date
We can add parameter in pipe using : character. We can show short, full or formatted
dates using this parameter. Add the below code in test.component.html file.
<div>
53
Angular 8
Chained pipes
We can combine multiple pipes together. This will be useful when a scenario associates
with more than one pipe that has to be applied for data transformation.
In the above example, if you want to show the date with uppercase letters, then we can
apply both Date and Uppercase pipes together.
<div>
Date with uppercase :- {{presentDate | date:'fullDate' | uppercase}} <br/>
Date with lowercase :- {{presentDate | date:'medium' | lowercase}} <br/>
</div>
Here,
Date, Uppercase and Lowercase are pre-defined pipes. Let’s understand other types of
built-in pipes in next section.
Built-in Pipes
Angular 8 supports the following built-in pipes. We will discuss one by one in brief.
AsyncPipe
If data comes in the form of observables, then Async pipe subscribes to an observable
and returns the transmitted values.
54
Angular 8
Here,
The Async pipe performs subscription for time changing in every one seconds and returns
the result whenever gets passed to it. Main advantage is that, we don’t need to call
subscribe on our timeChange and don’t worry about unsubscribe, if the component is
removed.
<div>
Seconds changing in Time: {{ timeChange | async }}
</div>
Now, run the application, you could see the seconds changing on your screen.
CurrencyPipe
It is used to convert the given number into various countries currency format. Consider
the below code in test.component.ts file.
@Component({
selector: 'app-test',
template: `
<div style="text-align:center">
<h3> Currency Pipe</h3>
<p>{{ price | currency:'EUR':true}}</p>
<p>{{ price | currency:'INR' }}</p>
</div>
`,
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
ngOnInit() {
55
Angular 8
Currency Pipe
€20,000.00
₹20,000.00
SlicePipe
Slice pipe is used to return a slice of an array. It takes index as an argument. If you assign
only start index, means it will print till the end of values. If you want to print specific range
of values, then we can assign start and end index.
We can also use negative index to access elements. Simple example is shown below:
test.component.ts
@Component({
selector: 'app-test',
template: `
<div>
<h3>Start index:- {{Fruits | slice:2}}</h3>
<h4>Start and end index:- {{Fruits | slice:1:4}}</h4>
<h5>Negative index:- {{Fruits | slice:-2}}</h5>
<h6>Negative start and end index:- {{Fruits | slice:-4:-2}}</h6>
</div>
`,
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
Fruits = ["Apple","Orange","Grapes","Mango","Kiwi","Pomegranate"];
ngOnInit() {
}
Now run your application and you could see the below output on your screen:
56
Angular 8
Here,
{{Fruits | slice:2}} means it starts from second index value Grapes to till the
end of value.
{{Fruits | slice:1:4}} means starts from 1 to end-1 so the result is one to third
index values.
{{Fruits | slice:-2}} means starts from -2 to till end because no end value is
specified. Hence the result is Kiwi, Pomegranate.
{{Fruits | slice:-4:-2}} means starts from negative index -4 is Grapes to end-1
which is -3 so the result of index[-4,-3] is Grapes, Mango.
DecimalPipe
It is used to format decimal values. It is also considered as CommonModule. Let’s
understand a simple code in test.component.ts file,
@Component({
selector: 'app-test',
template: `
<div style="text-align:center">
<h3>Decimal Pipe</h3>
<p> {{decimalNum1 | number}} </p>
<p> {{decimalNum2 | number}} </p>
</div>
`,
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
Decimal Pipe
8.759
5.43
57
Angular 8
Formatting values
We can apply string format inside number pattern. It is based on the below format:
number:"{minimumIntegerDigits}.{minimumFractionDigits} -
{maximumFractionDigits}"
@Component({
template: `
<div style="text-align:center">
<p> Apply formatting:- {{decimalNum1 | number:'3.1'}} </p>
<p> Apply formatting:- {{decimalNum1 | number:'2.1-4'}} </p>
</div>
`,
})
Here,
{{decimalNum1 | number:’2.1-4’}} means two decimal places and minimum one and
maximum of four fractions allowed so it returns the below output:
PercentPipe
It is used to format number as percent. Formatting strings are same as DecimalPipe
concept. Simple example is shown below:
@Component({
selector: 'app-test',
template: `
<div style="text-align:center">
<h3>Decimal Pipe</h3>
<p> {{decimalNum1 | percent:'2.2'}} </p>
</div>
`,
styleUrls: ['./test.component.scss']
})
export class TestComponent {
decimalNum1: number = 0.8178;
Decimal Pipe
81.78%
JsonPipe
It is used to transform a JavaScript object into a JSON string. Add the below code in
test.component.ts file as follows:
@Component({
selector: 'app-test',
template: `
<div style="text-align:center">
<p ngNonBindable>{{ jsonData }}</p> (1)
<p>{{ jsonData }}</p>
<p ngNonBindable>{{ jsonData | json }}</p>
<p>{{ jsonData | json }}</p>
</div>
`,
styleUrls: ['./test.component.scss']
})
export class TestComponent {
jsonData = { id: 'one', name: { username: 'user1' }}
}
Now, run the application, you could see the below output on your screen:
{{ jsonData }}
(1)
[object Object]
{{ jsonData | json }}
ng g pipe digitcount
After executing the above command, you could see the response:
59
Angular 8
Let’s create a logic for counting digits in a number using Pipe. Open digitcount.pipe.ts
file and add the below code:
@Pipe({
name: 'digitcount'
})
export class DigitcountPipe implements PipeTransform {
}
}
Now, we have added logic for count number of digits in a number. Let’s add the final code
in test.component.ts file as follows:
@Component({
selector: 'app-test',
template: `
<div>
<p> DigitCount Pipe </p>
<h1>{{ digits | digitcount }}</h1>
</div>
`,
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
digits : number = 100;
ngOnInit() {
}
}
Now, run the application, you could see the below response:
DigitCount Pipe
Working example
Let us use the pipe in the our ExpenseManager application.
60
Angular 8
cd /go/to/expense-manager
ng serve
Here, we have used the date pipe to show the spend on date in the short format.
61
9. Angular 8 — Reactive Programming Angular 8
Reactive programming is a programming paradigm dealing with data streams and the
propagation of changes. Data streams may be static or dynamic. An example of static data
stream is an array or collection of data. It will have an initial quantity and it will not change.
An example for dynamic data stream is event emitters. Event emitters emit the data
whenever the event happens. Initially, there may be no events but as the time moves on,
events happens and it will gets emitted.
Reactive programming enables the data stream to be emitted from one source called
Observable and the emitted data stream to be caught by other sources called Observer
through a process called subscription. This Observable / Observer pattern or simple
Observer pattern greatly simplifies complex change detection and necessary updating in
the context of the programming.
JavaScript does not have the built-in support for Reactive Programming. RxJs is a
JavaScript Library which enables reactive programming in JavaScript. Angular uses Rxjs
library extensively to do below mentioned advanced concepts:
Observable
As learn earlier, Observable are data sources and they may be static or dynamic. Rxjs
provides lot of method to create Observable from common JavaScript Objects. Let us see
some of the common methods.
of - Emit any number of values in a sequence and finally emit a complete notification.
Here,
62
Angular 8
ajax - Fetch a url through AJAX and then emit the response.
Here,
https://httpbin.org is a free REST API service which will return the supplied body
content in the JSON format as specified below:
{
"args": {},
"data": "Hello",
"files": {},
"form": {},
"headers": {
"Accept":
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/
*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-US,en;q=0.9",
"Host": "httpbin.org",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36",
"X-Amzn-Trace-Id": "Root=1-5eeef468-015d8f0c228367109234953c"
},
"origin": "ip address",
"url": "https://httpbin.org/delay/1"
}
fromEvent - Listen to an HTML element’s event and then emit the event and its
property whenever the listened event fires.
Angular internally uses the concept extensively to provide data transfer between
components and for reactive forms.
Subscribing process
Subscribing to an Observable is quite easy. Every Observable object will have a method,
subscribe for the subscription process. Observer need to implement three callback
function to subscribe to the Observable object. They are as follows:
63
Angular 8
next - Receive and process the value emitted from the Observable
error - Error handling callback
complete - Callback function called when all data from Observable are emitted.
Once the three callback functions are defined, Observable’s subscribe method has to be
called as specified below:
// observer
const observer = {
next: (num: number) => { this.numbers.push(num); this.val1 += num },
error: (err: any) => console.log(err),
complete: () => console.log("Observation completed")
};
numbers$.subscribe(observer);
Here,
next method get the emitted number and then push it into the local variable,
this.numbers.
next method also adding the number to local variable, this.val1.
error method just writes the error message to console.
complete method also writes the completion message to console.
We can skip error and complete method and write only the next method as shown below:
Operations
Rxjs library provides some of the operators to process the data stream. Some of the
important operators are as follows:
map - Enables to map the data stream using callback function and to change the data
stream itself.
64
Angular 8
Let us create a sample application to try out the reaction programming concept learned in
this chapter.
ng new reactive
cd reactive
ng serve
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'Reactive programming concept';
apiMessage : string;
counter : number = 0;
ngOnInit() {
// Observable stream of data Observable<number>
65
Angular 8
// observer
const observer = {
next: (num: number) => { this.numbers.push(num);
this.val1 += num },
error: (err: any) => console.log(err),
complete: () => console.log("Observation
completed")
};
numbers$.subscribe(observer);
const clickEvent$ =
fromEvent(document.getElementById('counter'), 'click');
clickEvent$.subscribe( () => this.counter++ );
}
}
Here,
Used of, range, from, ajax and fromEvent methods to created Observable.
Used filter, map and pipe operator methods to process the data stream.
Callback functions catch the emitted data, process it and then store it in
component’s local variables.
66
Angular 8
<div>
The summation of numbers ( <span *ngFor="let num of numbers"> {{ num }}
</span> ) is {{ val1 }}
</div>
<div>
The summation of filtered numbers ( <span *ngFor="let num of
filteredNumbers"> {{ num }} </span> ) is {{ val2 }}
</div>
<div>
The summation of processed numbers ( <span *ngFor="let num of
processedNumbers"> {{ num }} </span> ) is {{ val3 }}
</div>
<div>
The response from the API is <em>{{ apiMessage }}</em>
</div>
<div>
<a id="counter" href="#">Click here</a> to increment the counter value.
The current counter value is {{ counter }}
<div>
Here,
Click the Click here link for five times. For each event, the event will be emitted and
forward to the Observer. Observer callback function will be called. The callback function
increment the counter for every click and the final result will be as shown below:
67
Angular 8
68
10. Angular 8 — Services and Dependency Angular 8
Injection
Also, Angular services may depend on another services to work properly. Dependency
resolution is one of the complex and time consuming activity in developing any application.
To reduce the complexity, Angular provides Dependency Injection pattern as one of the
core concept.
Let us learn, how to use Dependency Injection in Angular application in this chapter.
@Injectable()
export class DebugService {
constructor() { }
}
Here, @Injectable decorator converts a plain Typescript class into Angular service.
ModuleInjector @ root
ModuleInjector enforces the service to used only inside a specific module. ProvidedIn
meta data available in @Injectable has to be used to specify the module in which the
service can be used.
The value should refer to the one of the registered Angular Module (decorated with
@NgModule). root is a special option which refers the root module of the application.
The sample code is as follows:
69
Angular 8
@Injectable({
providedIn: 'root',
})
export class DebugService {
constructor() { }
}
ModuleInjector @ platform
Platform Injector is one level higher than ModuleInject and it is only in advanced and
rare situation. Every Angular application starts by executing
PreformBrowserDynamic().bootstrap method (see main.js), which is responsible for
bootstrapping root module of Angular application.
NullInjector
NullInjector is one level higher than platform level ModuleInjector and is in the top
level of the hierarchy. We could not able to register any service in the NullInjector. It
resolves when the required service is not found anywhere in the hierarchy and simply
throws an error.
ExpenseEntryListComponent
// import statement
import { DebugService } from '../debug.service';
// component decorator
@Component({
selector: 'app-expense-entry-list',
templateUrl: './expense-entry-list.component.html',
styleUrls: ['./expense-entry-list.component.css'],
providers: [DebugService]
})
70
Angular 8
viewProviders is similar to provider except it does not allow the service to be used
inside the component’s content created using ng-content directive.
ExpenseEntryListComponent
// import statement
import { DebugService } from '../debug.service';
// component decorator
@Component({
selector: 'app-expense-entry-list',
templateUrl: './expense-entry-list.component.html',
styleUrls: ['./expense-entry-list.component.css'],
viewProviders: [DebugService]
})
Parent component can use a child component either through its view or content. Example
of a parent component with child and content view is mentioned below:
<div>
child template in view
<child></child>
</div>
<ng-content></ng-content>
<div>
child template in view
</div>
Here,
child component is used in two place. One inside the parent’s view. Another inside
parent content.
Services will be available in child component, which is placed inside parent’s view.
Services will not be available in child component, which is placed inside parent’s
content.
71
Angular 8
72
Angular 8
Here,
First, component tries to find the service registered using viewProviders meta
data.
If not found, component tries to find the service registered using providers meta
data.
If not found, Component tries to find the service registered using ModuleInjector
If not found, component tries to find the service registered using PlatformInjector
If not found, component tries to find the service registered using NullInjector,
which always throws error.
The hierarchy of the Injector along with work flow of the resolving the service is as follows:
Resolution Modifier
As we learn in the previous chapter, the resolution of the service starts from component
and stops either when a service is found or NUllInjector is reached. This is the default
resolution and it can be changed using Resolution Modifier. They are as follows:
Self()
Self() start and stops the search for the service in its current ElementInjector itself.
SkipSelf()
SkipSelf() is just opposite to Self(). It skips the current ElementInjector and starts the
search for service from its parent ElementInjector.
73
Angular 8
Host()
Host() stop the search for the service in its host ElementInjector. Even if service
available up in the higher level, it stops at host.
Optional()
@Optional does not throws the error when the search for the service fails.
providers: [ DebugService ]
Here, DebugService is both token as well as the class, with which the service object has
to be created. The actual form of the provider is as follows:
Here, provides is the token and useClass is the class reference to create the service
object.
providers: [ DebugService,
{ provides: AnotherDebugService, userClass: DebugService }]
74
Angular 8
Value providers
The purpose of the Value providers is to supply the value itself instead of asking the DI to
create an instance of the service object. It may use existing object as well. The only
restriction is that the object should be in the shape of referenced service.
Here, DI provider just return the instance set in useValue option instead of creating a
new service object.
// Create value
export const MY_CONFIG: AppConfig = {
title: 'Dependency Injection'
};
// congfigure providers
providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }]
Factory providers
Factory Providers enables complex service creation. It delegates the creation of the object
to an external function. Factory providers has option to set the dependency for factory
object as well.
75
Angular 8
ngOnInit() {
this.debugService.info("Angular Application starts");
}
}
Here,
ExpenseEntryListComponent constructor set a parameter of type DebugService.
Angular Dependency Injector (DI) will try to find any service registered in the
application with type DebugService. If found, it will set an instance of DebugService
to ExpenseEntryListComponent component. If not found, it will throw an error.
cd /go/to/expense-manager
ng serve
ng g service debug
This will create two Typescript files (debug service & its test) as specified below:
@Injectable({
providedIn: 'root'
})
export class DebugService {
constructor() { }
}
Here,
76
Angular 8
Let us add a method, Info, which will print the message into the browser console.
@Component({
selector: 'app-expense-entry-list',
templateUrl: './expense-entry-list.component.html',
styleUrls: ['./expense-entry-list.component.css']
})
export class ExpenseEntryListComponent implements OnInit {
title: string;
expenseEntries: ExpenseEntry[];
constructor(private debugService: DebugService) { }
ngOnInit() {
this.debugService.info("Expense Entry List component initialized");
this.title = "Expense Entry List";
this.expenseEntries = this.getExpenseEntries();
}
// other coding
}
Here,
The result can be viewed using developer tools and it looks similar as shown below:
77
Angular 8
// src/app/debug.service.ts
@Injectable()
export class DebugService {
constructor() {
}
78
Angular 8
// src/app/expense-entry-list/expense-entry-list.component.ts
@Component({
selector: 'app-expense-entry-list',
templateUrl: './expense-entry-list.component.html',
styleUrls: ['./expense-entry-list.component.css']
providers: [DebugService]
})
Here, we have used providers meta data (ElementInjector) to register the service.
@Component({
selector: 'app-debug',
templateUrl: './debug.component.html',
styleUrls: ['./debug.component.css']
})
export class DebugComponent implements OnInit {
ngOnInit() {
this.debugService.info("Debug component gets service from Parent");
}
}
Here, we have not registered DebugService. So, DebugService will not be available if
used as parent component. When used inside a parent component, the service may
available from parent, if the parent has access to the service.
// existing content
<app-debug></app-debug>
<ng-content></ng-content>
// navigation code
<app-expense-entry-list>
<app-debug></app-debug>
</app-expense-entry-list>
Let us check the application and it will show DebugService template at the end of the
page as shown below:
Also, we could able to see two debug information from debug component in the console.
This indicate that the debug component gets the service from its parent component.
Let us change how the service is injected in the ExpenseEntryListComponent and how
it affects the scope of the service. Change providers injector to viewProviders injection.
viewProviders does not inject the service into the content child and so, it should fail.
viewProviders: [DebugService]
Check the application and you will see that the one of the debug component (used as
content child) throws error as shown below:
80
Angular 8
Let us remove the debug component in the templates and restore the application.
<app-debug></app-debug>
<ng-content></ng-content>
// navigation code
<app-expense-entry-list> </app-expense-entry-list>
providers: [DebugService]
81
11. Angular 8 — Http Client Programming Angular 8
Http client programming is a must needed feature in every modern web application.
Nowadays, lot of application exposes their functionality through REST API (functionality
over HTTP protocol). With this in mind, Angular Team provides extensive support to access
HTTP server. Angular provides a separate module, HttpClientModule and a service,
HttpClient to do HTTP programming.
Let us learn how to how to use HttpClient service in this chapter. Developer should have
a basic knowledge in Http programming to understand this chapter.
Let us create an Expense Rest API using express framework and then access it from our
ExpenseManager application using Angular HttpClient service.
cd /go/to/workspace
mkdir express-rest-api
cd expense-rest-api
npm init
npm init will ask some basic questions like project name (express-rest-api), entry point
(server.js), etc., as mentioned below:
82
Angular 8
git repository:
keywords:
author:
license: (ISC)
About to write to \path\to\workspace\expense-rest-api\package.json:
{
"name": "expense-rest-api",
"version": "1.0.0",
"description": "Rest api for Expense Application",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
83
Angular 8
module.exports = db
Here, we are creating a new sqlite database and load some sample data.
84
Angular 8
});
85
Angular 8
amount = ?,
category = ?,
location = ?,
spendOn = ?
WHERE id = ?`,
[data.item, data.amount, data.category, data.location,
data.spendOn, req.params.id],
function (err, result) {
if (err){
console.log(err);
res.status(400).json({"error": res.message})
return;
}
res.json(data)
});
})
app.use(function(req, res){
res.status(404);
});
Here, we create a basic CURD rest api to select, insert, update and delete expense entry.
Open a browser, enter http://localhost:8000/ and press enter. You will see below
response:
{
"message": "Ok"
}
Change the url to http://localhost:8000/api/expense and you will see all the expense
entries in JSON format.
86
Angular 8
[
{
"id": 1,
"item": "Pizza",
"amount": 10,
"category": "Food",
"location": "KFC",
"spendOn": "2020-05-26 10:10",
"createdOn": "2020-05-26 10:10"
},
{
"id": 2,
"item": "Pizza",
"amount": 14,
"category": "Food",
"location": "Mcdonald",
"spendOn": "2020-06-01 18:14",
"createdOn": "2020-05-01 18:14"
},
{
"id": 3,
"item": "Pizza",
"amount": 15,
"category": "Food",
"location": "KFC",
"spendOn": "2020-06-06 16:18",
"createdOn": "2020-06-06 16:18"
},
{
"id": 4,
"item": "Pizza",
"amount": 9,
"category": "Food",
"location": "Mcdonald",
"spendOn": "2020-05-28 11:10",
"createdOn": "2020-05-28 11:10"
},
{
"id": 5,
"item": "Pizza",
"amount": 12,
"category": "Food",
"location": "Mcdonald",
"spendOn": "2020-05-29 09:22",
"createdOn": "2020-05-29 09:22"
}
]
Finally, we created a simple CURD REST API for expense entry and we can access the
REST API from our Angular application to learn HttpClient module.
87
Angular 8
@NgModule({
imports: [
BrowserModule,
// import HttpClientModule after BrowserModule.
HttpClientModule,
]
})
export class AppModule {}
cd /go/to/expense-manager
ng serve
This will create two Typescript files (expense entry service & its test) as specified below:
88
Angular 8
Create a variable, httpOptions to set the Http Header option. This will be used during
the Http Rest API call by Angular HttpClient service.
private httpOptions = {
headers: new HttpHeaders( { 'Content-Type': 'application/json' })
};
@Injectable({
providedIn: 'root'
})
export class ExpenseEntryService {
private expenseRestUrl = 'api/expense';
private httpOptions = {
headers: new HttpHeaders( { 'Content-Type': 'application/json'
})
};
constructor(
private httpClient : HttpClient) { }
}
HTTP GET
HttpClient provides get() method to fetch data from a web page. The main argument is
the target web url. Another optional argument is the option object with below format:
89
Angular 8
{
headers?: HttpHeaders | {[header: string]: string | string[]},
observe?: 'body' | 'events' | 'response',
Here,
headers: HTTP Headers of the request, either as string, array of string or array of
HttpHeaders.
observe: Process the response and return the specific content of the response.
Possible values are body, response and events. The default option of observer
is body.
params: HTTP parameters of the request, either as string, array of string or array
of HttpParams.
reportProgress: Whether to report the progress of the process or not (true or
false).
responseType: Refers the format of the response. Possible values are
arraybuffer, blob, json and text.
withCredentials: Whether the request has credentials or not (true or false).
get() method returns the response of the request as Observable. The returned
Observable emit the data when the response is received from the server.
httpClient.get(url, options)
.subscribe( (data) => console.log(data) );
Typed Response
get() method has an option to return observables, which emits typed response as well.
The sample code to get typed response (ExpenseEntry) is as follows:
httpClient.get<T>(url, options)
.subscribe( (data: T) => console.log(data) );
Handling errors
Error handling is one of the important aspect in the HTTP programming. Encountering error
is one of the common scenario in HTTP programming.
Client side issues can occur due to network failure, misconfiguration, etc., If client
side error happens, then the get() method throws ErrorEvent object.
90
Angular 8
Server side issues can occur due to wrong url, server unavailability, server
programming errors, etc.,
httpClient.get(url, options)
.pipe(catchError(this.httpErrorHandler)
.subscribe( (data) => console.log(data) )
We can use rxjs library’s retry operator in this scenario as specified below:
httpClient.get(url, options)
.pipe(
retry(5),
catchError(this.httpErrorHandler))
.subscribe( (data) => console.log(data) )
cd /go/to/expense-manager
ng serve
91
Angular 8
getExpenseEntries() : Observable<ExpenseEntry[]> {
return this.httpClient.get<ExpenseEntry[]>(this.expenseRestUrl,
this.httpOptions)
.pipe(
retry(3),
catchError(this.httpErrorHandler)
);
}
Here,
getExpenseEntries() calls the get() method using expense end point and also
configures the error handler. Also, it configures httpClient to try for maximum of
3 times in case of failure. Finally, it returns the response from server as typed
(ExpenseEntry[]) Observable object.
getExpenseEntry is similar to getExpenseEntries() except it passes the id of the
ExpenseEntry object and gets ExpenseEntry Observable object.
@Injectable({
92
Angular 8
providedIn: 'root'
})
export class ExpenseEntryService {
private expenseRestUrl = 'http://localhost:8000/api/expense';
private httpOptions = {
headers: new HttpHeaders( { 'Content-Type': 'application/json'
})
};
getExpenseEntries() : Observable<ExpenseEntry[]> {
return this.httpClient.get<ExpenseEntry[]>(this.expenseRestUrl,
this.httpOptions)
.pipe(
retry(3),
catchError(this.httpErrorHandler)
);
}
93
Angular 8
getExpenseItems() {
this.restService.getExpenseEntries()
.subscribe( data => this.expenseEntries = data );
}
@Component({
selector: 'app-expense-entry-list',
templateUrl: './expense-entry-list.component.html',
styleUrls: ['./expense-entry-list.component.css'],
providers: [DebugService]
})
export class ExpenseEntryListComponent implements OnInit {
title: string;
expenseEntries: ExpenseEntry[];
constructor(private debugService: DebugService, private restService :
ExpenseEntryService ) { }
ngOnInit() {
this.debugService.info("Expense Entry List component initialized");
this.title = "Expense Entry List";
this.getExpenseItems();
}
getExpenseItems() {
this.restService.getExpenseEntries()
.subscribe( data => this.expenseEntries = data );
}
}
Finally, check the application and you will see the below response.
94
Angular 8
HTTP POST
HTTP POST is similar to HTTP GET except that the post request will send the necessary
data as posted content along with the request. HTTP POST is used to insert new record
into the system.
HttpClient provides post() method, which is similar to get() except it support extra
argument to send the data to the server.
HTTP PUT
HTTP PUT is similar to HTTP POST request. HTTP PUT is used to update existing record in
the system.
95
Angular 8
HTTP DELETE
HTTP DELETE is similar to http GET request. HTTP DELETE is used to delete entries in the
system.
96
12. Angular 8 — Angular Material Angular 8
cd /go/to/expense-manager
ng add @angular/material
Angular CLI will ask certain question regarding theme, gesture recognition and browser
animations. Select your any theme of your choice and then answer positively for gesture
recognition and browser animation.
Angular material packages each UI component in a separate module. Import all the
necessary module into the application through root module (src/app/app.module.ts)
@NgModule({
imports: [
MatTableModule,
MatButtonModule,
MatIconModule
]
})
97
Angular 8
ng serve
Working example
Some of the important UI elements provided by Angular Material package.
Form field
Input
Checkbox
Radio button
Select
Button
DatePicker
List
Card
Grid list
Table
Paginator
Tabs
98
Angular 8
Toolbar
Menu
Dialog
Snackbar
Progress bar
Icon
Divider
Using material component is quite easy and we will learn one of the frequently used
material component, Material Table by working on a sample project.
cd /go/to/expense-manager
<div class="mat-elevation-z8">
<table mat-table [dataSource]="expenseEntries">
<ng-container matColumnDef="item">
<th mat-header-cell *matHeaderCellDef> Item </th>
<td mat-cell *matCellDef="let element" style="text-align:
left"> {{element.item}} </td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef > Amount </th>
<td mat-cell *matCellDef="let element" style="text-align:
left"> {{element.amount}} </td>
</ng-container>
<ng-container matColumnDef="category">
<th mat-header-cell *matHeaderCellDef> Category </th>
<td mat-cell *matCellDef="let element" style="text-align:
left"> {{element.category}} </td>
</ng-container>
<ng-container matColumnDef="location">
<th mat-header-cell *matHeaderCellDef> Location </th>
<td mat-cell *matCellDef="let element" style="text-align:
99
Angular 8
<ng-container matColumnDef="spendOn">
<th mat-header-cell *matHeaderCellDef> Spend On </th>
<td mat-cell *matCellDef="let element" style="text-align:
left"> {{element.spendOn}} </td>
</ng-container>
Here,
ng serve
100
Angular 8
101
13. Angular 8 — Routing and Navigation Angular 8
Navigation is one of the important aspect in a web application. Even though a single page
application (SPA) does not have multiple page concept, it does moves from one view (list
of expenses) to another view (expense details). Providing clear and understandable
navigation elements decides the success of an application.
Configure Routing
Angular CLI provides complete support to setup routing during the application creation
process as well as during working an application. Let us create a new application with
router enabled using below command:
Angular CLI generate a new module, AppRoutingModuele for routing purpose. The
generated code is as follows:
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Here,
Imports RouterModule and Routes from @angular/router package.
RouterMoudle provides functionality to configure and execute routing in the
application.
Routes is the type used to setup the navigation rules.
Routes is the local variable (of type Routes) used to configure the actual navigation
rules of the application.
RouterMoudle.forRoot() method will setup the navigation rules configured in the
routes variable.
102
Angular 8
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Here,
AppComponent imports the AppRoutingModule module using imports meta data.
Angular CLI provides option to set routing in the existing application as well. The general
command to include routing in an existing application is as follows:
This will generate new module with routing features enabled. To enable routing feature in
the existing module (AppModule), we need to include extra option as specified below:
Here,
–module app configures the newly created routing module, AppRoutingModule in the
AppModule module.
cd /go/to/expense-manager
Output
103
Angular 8
Here,
Creating routes
Creating a route is simple and easy. The basic information to create a route is given below:
Here,
Routes is the variable in the AppRoutingModule.
about is the path and AboutComponent is the target / destination component.
When user requests http://localhost:4200/about url, the path matches with about
rule and then AboutComponent will be called.
Accessing routes
Let us learn how to use the configured routes in the application.
<router-outlet></router-outlet>
Here,
Sometime, we need to access routing inside the component instead of template. Then, we
need to follow below steps:
104
Angular 8
Here,
this.router.navigate(['about']);
Here,
Here,
Route ordering
Route ordering is very important in a route configuration. If same path is configured
multiple times, then the first matched path will get called. If the first match fails due to
some reason, then the second match will get called.
Redirect routes
Angular route allows a path to get redirected to another path. redirectTo is the option to
set redirection path. The sample route is as follows:
Here,
redirectTo sets about as the redirection path if the actual path matches empty
string.
Wildcard routes
105
Angular 8
Wildcard route will match any path. It is created using ** and will be used to handle non
existing path in the application. Placing the wildcard route at the end of the configuration
make it called when other path is not matched.
Here,
If a non existent page is called, then the first two route gets failed. But, the final wildcard
route will succeed and the PageNotFoundComponent gets called.
Here, we have attached id in the path. id can be accessed in the ItemComponent using
two techniques.
Using Observable.
Using snapshot (non-observable option).
Using Observable
Angular provides a special interface, paramMap to access the parameter of the path.
parmaMap has following methods:
has(name) - Returns true if the specified name is available in the path (parameter
list).
get(name) - Returns the value of the specified name in the path (parameter list).
getAll(name) - Returns the multiple value of the specified name in the path. get()
method returns only the first value when multiple values are available.
keys - Returns all parameter available in the path.
106
Angular 8
ngOnInit() {
this.route.paramMap.subscribe(params => {
this.id = params.get('id);
});
}
this.item$ = this.route.paramMap.pipe(
switchMap(params => {
this.selectedId = Number(params.get('id'));
return this.service.getItem(this.selectedId);
})
);
Using snapshot
snapshot is similar to Observable except, it does not support observable and get the
parameter value immediately.
let id = this.route.snapshot.paramMap.get('id');
Nested routing
In general, router-outlet will be placed in root component (AppComponent) of the
application. But, router-outlet can be used in any component. When router-outlet is used
in a component other then root component, the routes for the particular component has
to be configured as the children of the parent component. This is called Nested routing.
<h2>Item Component</h2>
<nav>
<ul>
<li><a routerLink="view">View</a></li>
<li><a routerLink="edit">Edit</a></li>
</ul>
</nav>
<router-outlet></router-outlet>
The route for the ItemComponent has to be configured as Nested routing as specified
below:
107
Angular 8
component: ItemComponent,
children: [
{
path: 'view',
component: ItemViewComponent
},
{
path: 'edit',
component: ItemEditComponent
}
]
}]
Working example
Let us apply the routing concept learned in this chapter in our ExpenseManager
application.
cd /go/to/expense-manager
Output
Here,
108
Angular 8
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Here, we have added route for our expense list and expense details component.
<router-outlet></router-outlet>
109
Angular 8
<th>Amount</th>
<th>Category</th>
<th>Location</th>
<th>Spent On</th>
<th>View</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let entry of expenseEntries">
<th scope="row">{{ entry.item }}</th>
<th>{{ entry.amount }}</th>
<td>{{ entry.category }}</td>
<td>{{ entry.location }}</td>
<td>{{ entry.spendOn | date: 'medium' }}</td>
<td><a routerLink="../expenses/detail/{{ entry.id
}}">View</a></td>
</tr>
</tbody>
</table>
Here, we have updated the expense list table and added a new column to show the view
option.
this.expenseEntry$ = this.route.paramMap.pipe(
switchMap(params => {
this.selectedId = Number(params.get('id'));
return
this.restService.getExpenseEntry(this.selectedId);
}));
goToList() {
this.router.navigate(['/expenses']);
}
110
Angular 8
@Component({
selector: 'app-expense-entry',
templateUrl: './expense-entry.component.html',
styleUrls: ['./expense-entry.component.css']
})
export class ExpenseEntryComponent implements OnInit {
title: string;
expenseEntry$ : Observable<ExpenseEntry>;
expenseEntry: ExpenseEntry = {} as ExpenseEntry;
selectedId: number;
ngOnInit() {
this.title = "Expense Entry";
this.expenseEntry$ = this.route.paramMap.pipe(
switchMap(params => {
this.selectedId = Number(params.get('id'));
return
this.restService.getExpenseEntry(this.selectedId);
}));
goToList() {
this.router.navigate(['/expenses']);
}
}
ng serve
111
Angular 8
Clicking the view option of the first entry will navigate to details page and show the
selected expense entry as shown below:
112
14. Angular 8 — Animations Angular 8
Animation gives the web application a refreshing look and rich user interaction. In HTML,
animation is basically the transformation of HTML element from one CSS style to another
over a specific period of time. For example, an image element can be enlarged by changing
its width and height.
If the width and height of the image is changed from initial value to final value in steps
over a period of time, say 10 seconds, then we get an animation effect. So, the scope of
the animation depends on the feature / property provided by the CSS to style a HTML
element.
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule
],
declarations: [ ],
bootstrap: [ ]
})
export class AppModule { }
@Component({
animations: [
// animation functionality goes here
]
})
export class MyAnimationComponent
113
Angular 8
Concepts
In angular, we need to understand the five core concept and its relationship to do
animation.
State
State refers the specific state of the component. A component can have multiple defined
state. The state is created using state() method. state() method has two arguments.
animations: [
...
state('start', style( { width: 200px; } ))
...
]
Style
Style refers the CSS style applied in a particular state. style() method is used to style the
particular state of a component. It uses the CSS property and can have multiple items.
animations: [
...
state('start', style( { width: 200px; opacity: 1 } ))
...
]
Here, start state defines two CSS property, width with value 200px and opacity with
value 1.
Transition
Transition refers the transition from one state to another. Animation can have multiple
transition. Each transition is defined using transition() function. transition() takes two
argument.
Specifies the direction between two transition state. For example, start => end
refers that the initial state is start and the final state is end. Actually, it is an
expression with rich functionality.
Specifies the animation details using animate() function.
animations: [
...
transition('start => end', [
animate('1s')
])
...
]
114
Angular 8
Here, transition() function defines the transition from start state to end state with
animation defined in animate() method.
Animation
Animation defines the way the transition from one state to another take place.
animation() function is used to set the animation details. animate() takes a single
argument in the form of below expression:
duration refers the duration of the transition. It is expressed as 1s, 100ms, etc.,
delay refers the delay time to start the transition. It is expressed similar to duration
easing refers how do to accelerates / decelerates the transition in the given time
duration.
Trigger
Every animation needs a trigger to start the animation. trigger() method is used to set
all the animation information such as state, style, transition and animation in one place
and give it a unique name. The unique name is used further to trigger the animation.
animations: [
trigger('enlarge', [
state('start', style({
height: '200px',
})),
state('end', style({
height: '500px',
})),
transition('start => end', [
animate('1s')
]),
transition('end => start', [
animate('0.5s')
])
]),
]
Here, enlarge is the unique name given to the particular animation. It has two state and
related styles. It has two transition one from start to end and another from end to start.
End to start state do the reverse of the animation.
<div [@triggerName]="expression">...</div>;
For example,
Here,
115
Angular 8
If isEnlarge value is changed to true, then end state will be set and it triggers
start => end transition.
If isEnlarge value is changed to false, then start state will be set and it triggers
end => start transition.
cd /go/to/workspace
ng new animation-app
cd animation-app
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Add animation functionality, which will animate the image during the enlarging / shrinking
of the image.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
animations: [
trigger('enlarge', [
state('start', style({
height: '150px'
116
Angular 8
})),
state('end', style({
height: '250px'
})),
transition('start => end', [
animate('1s 2s')
]),
transition('end => start', [
animate('1s 2s')
])
])
]
})
<br />
triggerAnimation() {
this.isEnlarge = !this.isEnlarge;
if(this.isEnlarge)
this.buttonText = "Shrink";
else
this.buttonText = "Enlarge";
}
}
Attach the animation in the image tag. Also, attach the click event for the button.
<br />
117
Angular 8
<br />
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
animations: [
trigger('enlarge', [
state('start', style({
height: '150px'
})),
state('end', style({
height: '250px'
})),
transition('start => end', [
animate('1s 2s')
]),
transition('end => start', [
animate('1s 2s')
])
])
]
})
export class AppComponent {
title = 'Animation Application';
isEnlarge: boolean = false;
buttonText: string = "Enlarge";
triggerAnimation() {
this.isEnlarge = !this.isEnlarge;
if(this.isEnlarge)
this.buttonText = "Shrink";
else
this.buttonText = "Enlarge";
}
}
118
Angular 8
<br />
ng serve
Click the enlarge button, it will enlarge the image with animation. The result will be as
shown below:
Click the button again to shrink it. The result will be as shown below:
119
Angular 8
120
15. Angular 8 — Forms Angular 8
Forms are used to handle user input data. Angular 8 supports two types of forms. They
are Template driven forms and Reactive forms. This section explains about Angular 8
forms in detail.
Configure Forms
Before understanding forms, let us learn how to configure forms in an application. To
enable template driven forms, first we need to import FormsModule in app.module.ts.
It is given below:
imports: [
BrowserModule,
AppRoutingModule,
FormsModule //Assign FormsModule
],
Once, FormsModule is imported, the application will be ready for form programming.
Open command prompt and create new Angular application using below command:
cd /go/to/workspace
ng new template-form-app
cd template-form-app
...
121
Angular 8
@NgModule({
declarations: [
AppComponent,
TestComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
122
Angular 8
ngOnInit() {
}
onClickSubmit(result) {
console.log("You have entered : " + result.username);
}
}
<app-test></app-test>
Finally, start your application (if not done already) using the below command:
ng serve
Now, run your application and you could see the below response:
Enter Peter in input text field and enter submit. onClickSubmit function will be called
and user entered text Peter will be send as an argument. onClickSubmit will print the
user name in the console and the output is as follows:
123
Angular 8
Reactive Forms
Reactive Forms is created inside component class so it is also referred as model driven
forms. Every form control will have an object in the component and this provides greater
control and flexibility in the form programming. Reactive Form is based on structured
data model. Let’s understand how to use Reactive forms in angular.
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule //Assign here
]
Open command prompt and create new Angular application using below command:
cd /go/to/workspace
ng new reactive-form-app
cd reactive-form-app
...
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
TestComponent
],
imports: [
BrowserModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
125
Angular 8
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
userName;
formdata;
ngOnInit() {
this.formdata = new FormGroup({
userName: new FormControl("Tutorialspoint")
});
}
onClickSubmit(data) {this.userName = data.userName;}
}
Here,
<div>
<form [formGroup]="formdata" (ngSubmit)="onClickSubmit(formdata.value)" >
<input type= text" name="userName" placeholder="userName"
formControlName = "userName">
<br/>
<br/>
<input type="submit" value="Click here">
</form>
</div>
<p> Textbox result is: {{userName}} </p>
Here,
<app-test></app-test>
Finally, start your application (if not done already) using the below command:
126
Angular 8
ng serve
Now, run your application and you could see the below response:
Enter Tutorialspoint in input text field and enter submit. onClickSubmit function will be
called and user entered text Peter will be send as an argument.
127
16. Angular 8 — Form Validation Angular 8
Form validation is an important part of web application. It is used to validate whether the
user input is in correct format or not.
RequiredValidator
Let’s perform simple required field validation in angular.
cd /go/to/reactive-form-app
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
}
}
Here,
We have used form builder to handle all the validation. Constructor is used to create a
form with the validation rules.
128
Angular 8
<div>
<h2>
Required Field validation
</h2>
<form [formGroup]="requiredForm" novalidate>
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div *ngIf="requiredForm.controls['name'].invalid &&
requiredForm.controls['name'].touched" class="alert alert-danger">
<div *ngIf="requiredForm.controls['name'].errors.required">
Name is required.
</div>
</div>
</form>
<p>Form value: {{ requiredForm.value | json }}</p>
<p>Form status: {{ requiredForm.status | json }}</p>
</div>
Here,
Finally, start your application (if not done already) using the below command:
ng serve
Now run your application and put focus on text box. Then, it will use show Name is
required as shown below:
129
Angular 8
If you enter text in the textbox, then it is validated and the output is shown below:
PatternValidator
PatternValidator is used to validate regex pattern. Let’s perform simple email validation.
cd /go/to/reactive-form-app
130
Angular 8
'@angular/forms';
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
myForm() {
this.requiredForm = this.fb.group({
email: ['', [Validators.required,
Validators.pattern("^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-
z]{2,4}$")] ]
});
}
ngOnInit()
{
}
}
Here,
<div>
<h2>
Pattern validation
</h2>
<form [formGroup]="requiredForm" novalidate>
<div class="form-group">
<label class="center-block">Email:
<input class="form-control" formControlName="email">
</label>
</div>
<div *ngIf="requiredForm.controls['email'].invalid &&
requiredForm.controls['email'].touched" class="alert alert-danger">
<div *ngIf="requiredForm.controls['email'].errors.required">
Email is required.
</div>
</div>
</form>
<p>Form value: {{ requiredForm.value | json }}</p>
<p>Form status: {{ requiredForm.status | json }}</p>
</div>
131
Angular 8
Here, we have created the email control and called email validator.
Run your application and you could see the below result:
132
17. Angular 8 — Authentication and Angular 8
Authorization
Authentication is the process matching the visitor of a web application with the pre-
defined set of user identity in the system. In other word, it is the process of recognizing
the user’s identity. Authentication is very important process in the system with respect to
security.
Authorization is the process of giving permission to the user to access certain resource
in the system. Only the authenticated user can be authorised to access a resource.
Guards in Routing
In a web application, a resource is referred by url. Every user in the system will be allowed
access a set of urls. For example, an administrator may be assigned all the url coming
under administration section.
As we know already, URLs are handled by Routing. Angular routing enables the urls to
be guarded and restricted based on programming logic. So, a url may be denied for a
normal user and allowed for an administrator.
Angular provides a concept called Router Guards which can be used to prevent
unauthorised access to certain part of the application through routing. Angular provides
multiple guards and they are as follows:
Working example
Let us try to add login functionality to our application and secure it using CanActivate
guard.
cd /go/to/expense-manager
ng serve
133
Angular 8
@Injectable({
providedIn: 'root'
})
export class AuthService {
return of(this.isUserLoggedIn).pipe(
delay(1000),
tap(val => {
console.log("Is User Authentication is successful: " +
val);
})
);
}
logout(): void {
this.isUserLoggedIn = false;
localStorage.removeItem('isUserLoggedIn');
}
constructor() { }
}
Here,
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
userName: string;
password: string;
formData: FormGroup;
ngOnInit() {
this.formData = new FormGroup({
userName: new FormControl("admin"),
password: new FormControl("admin"),
});
}
onClickSubmit(data: any) {
this.userName = data.userName;
this.password = data.password;
this.authService.login(this.userName, this.password)
.subscribe( data => {
console.log("Is Login Success: " + data);
if(data) this.router.navigate(['/expenses']);
});
}
}
Here,
135
Angular 8
Here,
.form-signin {
max-width: 330px;
136
Angular 8
padding: 15px;
margin: 0 auto;
}
input {
margin-bottom: 20px;
}
@Component({
selector: 'app-logout',
templateUrl: './logout.component.html',
styleUrls: ['./logout.component.css']
})
export class LogoutComponent implements OnInit {
ngOnInit() {
this.authService.logout();
this.router.navigate(['/']);
}
Here,
137
Angular 8
@Injectable({
providedIn: 'root'
})
export class ExpenseGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean | UrlTree {
let url: string = state.url;
return this.checkLogin(url);
}
Here,
checkLogin will check whether the localStorage has the user information and if it
is available, then it returns true.
If the user is logged in and goes to login page, it will redirect the user to expenses
page
If the user is not logged in, then the user will be redirected to login page.
138
Angular 8
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Here,
Open AppComponent template and add two login and logout link.
</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/expenses">Report</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Add Expense</a>
</li>
<li class="nav-item">
139
Angular 8
<ng-template #isLogOut>
<a class="nav-link"
routerLink="/login">Login</a>
</ng-template>
</li>
</ul>
</div>
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
ngOnInit() {
let storeData = localStorage.getItem("isUserLoggedIn");
console.log("StoreData: " + storeData);
this.isUserLoggedIn = false;
}
}
Here, we have added the logic to identify the user status so that we can show login /
logout functionality.
140
Angular 8
imports: [
ReactiveFormsModule
]
Now, run the application and the application opens the login page.
Enter admin and admin as username and password and then, click submit. The
application process the login and redirects the user to expense list page as shown below:
141
Angular 8
142
18. Angular 8 — Web Workers Angular 8
Web workers enables JavaScript application to run the CPU-intensive in the background
so that the application main thread concentrate on the smooth operation of UI. Angular
provides support for including Web workers in the application. Let us write a simple Angular
application and try to use web workers.
cd /go/to/workspace
ng new web-worker-sample
cd web-worker-sample
npm run start
Here,
// tsconfig.worker.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/worker",
"lib": [
"es2018",
"webworker"
],
143
Angular 8
"types": []
},
"include": [
"src/**/*.worker.ts"
]
}
Here,
Here,
Basically, it excludes all the worker from compiling as it has separate configuration.
Here,
// src/app/app.worker.ts
addEventListener('message', ({ data }) => {
const response = `worker response to ${data}`;
postMessage(response);
});
Here,
A web worker is created. Web worker is basically a function, which will be called when a
message event is fired. The web worker will receive the data send by the caller, process it
and then send the response back to the caller.
144
Angular 8
Here,
Restart the application. Since the angular.json file is changed, which is not watched by
Angular runner, it is necessary to restart the application. Otherwise, Angular does not
identify the new web worker and does not compile it.
return true;
}
idx++;
console.log(idx);
}
return idx - 1;
}
}
Here,
145
Angular 8
Import the new created prime number class into src/app/app.worker.ts and change
the logic of the web worker to find nth prime number.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Web worker sample';
prime10 : number = 0;
prime10000 : number = 0;
find10thPrimeNumber() {
this.prime10 = PrimeCalculator.findNthPrimeNumber(10);
}
find10000thPrimeNumber() {
if (typeof Worker !== 'undefined') {
// Create a new
const worker = new Worker('./app.worker', { type:
'module' });
worker.onmessage = ({ data }) => {
this.prime10000 = data;
};
worker.postMessage(10000);
} else {
// Web Workers are not supported in this environment.
// You should add a fallback so that your program still
executes correctly.
}
}
}
Here,
146
Angular 8
<div>
<a href="#" (click)="find10thPrimeNumber()">Click here</a> to find 10th
prime number
<div>The 10<sup>th</sup> prime number is {{ prime10 }}</div> <br/>
<a href="#" (click)="find10000thPrimeNumber()">Click here</a> to find
10000th prime number
<div>The 10000<sup>th</sup> prime number is {{ prime10000 }}</div>
</div>
Here,
Finding 10000th prime number will take few seconds, but it will not affect other process
as it is uses web workers. Just try to find the 10000th prime number first and then, the
10th prime number.
Since, the web worker is calculating 10000th prime number, the UI does not freeze. We
can check 10th prime number in the meantime. If we have not used web worker, we could
not do anything in the browser as it is actively processing the 10000th prime number.
Click and try to find the 10000th prime number and then try to find the 10th prime number.
The application finds the 10th prime number quite fast and shows it. The application is still
processing in the background to find the 10000th prime number.
147
Angular 8
Web worker enhances the user experience of web application by doing the complex
operation in the background and it is quite easy to do it in Angular Application as well.
148
19. Angular 8 — Service Workers and PWA Angular 8
Progressive web apps (PWA) are normal web application with few enhancements and
behaves like a native application. PWA apps does not depends on network to work. PWA
caches the application and renders it from local cache. It regularly checks the live version
of the application and then caches the latest version in the background.
PWA can be installed in the system like native application and shortcut can be shown in
the desktop. Clicking the shortcut will open the application in browser with local cache
even without any network available in the system.
Service workers is separate from web pages. It does not able to access DOM objects.
Instead, Service Workers interact with web pages through PostMessage interface.
Browser support - Even though lot of browser supports the PWA app, IE, Opera
mini and few other does not provides the PWA support.
HTTPS delivery - The application needs to be delivered through HTTPS protocol.
One exception of the https support is localhost for development purpose.
cd /go/to/workspace
ng new pwa-sample
cd pwa-sample
ng add @angular/pwa --project pwa-sample
ng build --prod
PWA application does not run under Angular development server. Install, a simple web
server using below command:
Run the web server and set our production build of the application as root folder.
149
Angular 8
Normal application stops working if network is set to Offline but, PWA application works
fine as shown below:
150
20. Angular 8 — Server Side Rendering Angular 8
Server side Rendering (SSR) is a modern technique to convert a Single Page Application
(SPA) running in the browser into a server based application. Usually, in SPA, the server
returns a simple index.html file with the reference to the JavaScript based SPA app. The
SPA app take over from there, configure the entire application, process the request and
then send the final response.
But in SSR supported application, the server as well do all the necessary configuration and
then send the final response to the browser. The browser renders the response and start
the SPA app. SPA app takeover from there and further request are diverted to SPA app.
The flow of SPA and SSR is as shown in below diagram.
151
Angular 8
Converting a SPA application to SSR provides certain advantages and they are as follows:
Speed - First request is relatively fast. One of the main drawback of SPA is slow
initial rendering. Once the application is rendered, SPA app is quite fast. SSR fixes
the initial rendering issue.
152
Angular 8
SEO Friendly - Enables the site to be SEO friendly. Another main disadvantage of
SPA is not able to crawled by web crawler for the purpose of SEO. SSR fixes the
issue.
Angular Universal
To enable SSR in Angular, Angular should be able to rendered in the server. To make it
happen, Angular provides a special technology called Angular Universal. It is quite new
technology and it is continuously evolving. Angular Universal knows how to render Angular
application in the server. We can upgrade our application to Angular Universal to support
SSR.
153
21. Angular 8 — Internationalization (i18n) Angular 8
Internationalization (i18n) is a must required feature for any modern web application.
Internationalization enables the application to target any language in the world.
Localization is a part of the Internationalization and it enables the application to render in
a targeted local language. Angular provides complete support for internationalization and
localization feature.
Let us learn how to create a simple hello world application in different language.
cd /go/to/workspace
ng new i18n-sample
cd i18n-sample
npm run start
<div>Hello</div>
<div>The Current time is {{ currentDate | date : 'medium' }}</div>
ng add @angular/localize
LOCALE_ID is the Angular variable to refer the current locale. By default, it is set as
en_US. Let us change the locale by using in the provider in AppModule.
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [ { provide: LOCALE_ID, useValue: 'hi' } ],
154
Angular 8
bootstrap: [AppComponent]
})
export class AppModule { }
Here,
Import the locale data from @angular/common/locales/hi and then, register it using
registerLocaleData method as specified below:
registerLocaleData(localeHi);
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'Internationzation Sample';
}
Create a local variable, CurrentDate and set current time using Date.now().
<div>Hello</div>
<div>The Current time is {{ currentDate | date : 'medium' }}</div>
Check the result and you will see the date is specified using hi locale.
155
Angular 8
We have changed the date to current locale. Let us change other content as well. To do
it, include i18n attribute in the relevant tag with format, title|description@@id.
Here,
156
Angular 8
</trans-unit>
<trans-unit id="currentTime" datatype="html">
<source>
The Current time is <x id="INTERPOLATION" equiv-text="{{
currentDate | date : 'medium' }}"/>
</source>
<context-group purpose="location">
<context context-
type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">5</context>
</context-group>
<note priority="1" from="description">Specifiy the current time</note>
<note priority="1" from="meaning">time</note>
</trans-unit>
</body>
</file>
</xliff>
Open the file with Unicode text editor. Locate source tag and duplicate it with target tag
and then change the content to hi locale. Use google translator to find the matching text.
The changed content is as follows:
Open angular.json and place below configuration under build -> configuration.
"hi": {
"aot": true,
"outputPath": "dist/hi/",
"i18nFile": "src/locale/messages.hi.xlf",
"i18nFormat": "xlf",
"i18nLocale": "hi",
"i18nMissingTranslation": "error",
"baseHref": "/hi/"
},
"en": {
"aot": true,
"outputPath": "dist/en/",
"i18nFile": "src/locale/messages.xlf",
"i18nFormat": "xlf",
"i18nLocale": "en",
"i18nMissingTranslation": "error",
"baseHref": "/en/"
}
157
Angular 8
Here,
"hi": {
"browserTarget": "i18n-sample:build:hi"
},
"en": {
"browserTarget": "i18n-sample:build:en"
}
We have added the necessary configuration. Stop the application and run below command:
Here,
Navigate to http://localhost:4200/hi and you will see the Hindi localised content.
158
22. Angular 8 — Accessibility Angular 8
While using attribute binding, use attr. prefix for ARIA attributes.
Use Angular material component for Accessibility. Some of the useful components
are LiveAnnouncer and cdkTrapFocus
Use native HTML elements wherever possible because native HTML element
provides maximum accessibility features. When creating a component, select
native html element matching your use case instead of redeveloping the native
functionality.
Use NavigationEnd to track and control the focus of the application as it greatly
helps in accessibility.
159
23. Angular 8 — CLI Commands Angular 8
Angular CLI helps developers to create projects easily and quickly. As we know already,
Angular CLI tool is used for development and built on top of Node.js, installed from
NPM.This chapter explains about Angular 8 CLI commands in detail.
Verify CLI
Before moving to Angular CLI commands, we have to ensure that Angular CLI is installed
on your machine. If it is installed, you can verify it by using the below command:
ng version
If CLI is not installed, then use the below command to install it.
New command
To create an application in Angular, use the below syntax:
ng new <project-name>
160
Angular 8
Example
ng new CustomerApp
Generate Command
It is used to generate or modify files based on a schematic. Type the below command
inside your angular project:
ng generate
Or, you can simply type generate as g. You can also use the below syntax:
ng g
Let’s understand some of the repeatedly used ng generate schematics in next section.
Create a component
Components are building block of Angular. To create a component in angular use the below
syntax:
ng g c <component-name>
For example, if user wants to create a Details component then use the below code:
ng g c Details
After using this command, you could see the below response:
161
Angular 8
Create a class
It is used to create a new class in Angular. It is defined below:
ng g class <class-name>
If you want to create a customer class, then type the below command:
ng g class Customer
After using this command, you could see the below response:
Create a pipe
Pipes are used for filtering the data. It is used to create a custom pipe in Angular. It is
defined below:
ng g pipe <pipe-name>
If you want to create a custom digit counts in a pipe, then type the below command:
ng g pipe DigitCount
After using this command, you could see the below response:
Create a directive
It is used to create a new directive in Angular. It is defined below:
ng g directive <directive-name>
If you want to create a UnderlineText directive, then type the below command:
ng g directive UnderlineText
After using this command, you could see the below response:
162
Angular 8
Create a module
It is used to create a new module in Angular. It is defined below:
ng g module <module-name>
If you want to create a user information module, then type the below command:
ng g module Userinfo
After using this command, you could see the below response:
Create an interface
It is used to create an interface in Angular. It is given below:
ng g interface <interface-name>
If you want to create a customer class, then type the below command:
ng g interface CustomerData
After using this command, you could see the below response:
ng g webWorker <webWorker-name>
If you want to create a customer class, then type the below command:
ng g webWorker CustomerWebWorker
After using this command, you could see the below response:
Create a service
163
Angular 8
ng g service <service-name>
If you want to create a customer class, then type the below command:
ng g service CustomerService
After using this command, you could see the below response:
Create an enum
It is used to create an enum in Angular. It is given below:
ng g enum <enum-name>
If you want to create a customer class, then type the below command:
ng g enum CustomerRecords
After using this command, you could see the below response:
Add command
It is used to add support for an external library to your project. It is specified by the below
command:
ng add [name]
Build command
It is used to compile or build your angular app. It is defined below:
ng build
After using this command, you could see the below response:
Config command
It is used to retrieve or set Angular configuration values in the angular.json file for the
workspace. It is defined below:
ng config
164
Angular 8
After using this command, you could see the below response:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"MyApp": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
.............................
.............................
Doc command
It is used to open the official Angular documentation (angular.io) in a browser, and
searches for a given keyword.
ng doc <keyword>
For example, if you search with component as ng g component then, it will open the
documentation.
e2e command
It is used to build and serves an Angular app, then runs end-to-end tests using Protractor.
It is stated below:
Help command
It lists out available commands and their short descriptions. It is stated below:
ng help
Serve command
It is used to build and serves your app, rebuilding on file changes. It is given below:
ng serve
Test command
Runs unit tests in a project. It is mentioned below:
ng test
165
Angular 8
Update command
Updates your application and its dependencies. It is given below:
ng update
Version command
Shows Angular CLI version. It is stated below:
ng version
166
24. Angular 8 — Testing Angular 8
Testing is a very important phase in the development life cycle of an application. It ensures
an application quality. It needs careful planning and execution.
Unit Test
Unit testing is the easiest method to test an application. It is based on ensuring the
correctness of a piece of code or a method of a class. But, it does not reflect the real
environment and subsequently. It is the least option to find the bugs.
Generally, Angular 8 uses Jasmine and Karma configurations. To perform this, first you
need to configure in your project, using the below command:
ng test
Now, Chrome browser also opens and shows the test output in the “Jasmine HTML
Reporter”. It looks similar to this,
167
Angular 8
ng e2e
168
25. Angular 8 — Ivy Compiler Angular 8
Ivy Compiler is the latest compiler for Angular application released by Angular Team.
Currently, Angular is using View Engine compiler to compile Angular application.
In Just In Time (JIT) compilation, the compiler will be bundled along with the application
and send to the browser. Angular application will be compiled in the browser and run just
before the execution of application.
Eventhough JIT provides certain advanced feature, JIT slows down the compilation and
also the app bundle will be double the size produced by AOT compiler as it includes
compiler as well.
In AOT compilation, the compiler will emit optimised code ready to run inside the browser
without any addition step. It will reduce the size of the bundle as well as reduce the
compilation time and startup time of the application.
Optimised code.
Faster build time.
Reduced bundle size.
Better performance.
Open angular.json and set the aot option (projects -> -> architect -> build ->
configurations -> production) of the project to true.
{
"projects": {
"my-existing-project": {
"architect": {
169
Angular 8
"build": {
"options": {
...
"aot": true,
}
}
}
}
}
}
{
...
"angularCompilerOptions": {
"enableIvy": true
}
Compile and run the application and get benefited by Ivy Compiler.
170
26. Angular 8 — Building with Bazel Angular 8
Bazel is an advanced build and test tool. It supports lot of features suitable for large
projects.
Angular supports building the application using bazel. Let us see how to use bazel to
compile Angular application.
ng add @angular/bazel
ng new --collection=@angular/bazel
ng build --leaveBazelFilesOnDisk
Here,
leaveBazelFilesOnDisk option will leave the bazel files created during build process,
which we can use to build the application directly using bazel.
To build application using bazel directly, install @bazel/bazelisk and then, use bazelisk
build command.
171
27. Angular 8 — Backward Compatibility Angular 8
Angular maintains documentation and guides of all version. For example, Angular
documentation for version 7 can be checked @ https://v7.angular.io. Angular also
provides a detailed upgrade path through https://update.angular.io/ site.
To update Angular application written from previous version, use below command inside
the project directory:
HttpModule module and its associated Http service is removed. Use HttpClient
service from HttpClientModule module.
/deep/, >>> and :ng-deep component selectors are removed.
Angular default version of TypeScript is 3.4.
Node version supported by Angular is v10 and later.
@ViewChild() and ContentChild() decorator behaviour is changed from dynaic
to static.
Lazy loading string syntax in router module is removed and only function based is
supported.
loadChildren: './lazy/lazy.module#LazyModule'
loadChildren: () => import('./lazy/lazy.module'
172
28. Angular 8 — Working Example Angular 8
Here, we will study about the complete step by step working example with regards to
Angular 8.
Let us create an Angular application to check our day to day expenses. Let us give
ExpenseManager as our choice for our new application.
Create an application
Use below command to create the new application.
cd /path/to/workspace
ng new expense-manager
Here,
new is one of the command of the ng CLI application. It will be used to create new
application. It will ask some basic question in order to create new application. It is enough
to let the application choose the default choices. Regarding routing question as mentioned
below, specify No.
Once the basic questions are answered, the ng CLI application create a new Angular
application under expense-manager folder.
cd expense-manager
ng serve
Let us fire up a browser and opens http://localhost:4200. The browser will show the
application as shown below:
173
Angular 8
Let us change the title of the application to better reflect our application. Open
src/app/app.component.ts and change the code as specified below:
174
Angular 8
Add a component
Create a new component using ng generate component command as specified below:
Output
Here,
175
Angular 8
@Component({
selector: 'app-expense-entry',
templateUrl: './expense-entry.component.html',
styleUrls: ['./expense-entry.component.css']
})
export class ExpenseEntryComponent implements OnInit {
title: string;
constructor() { }
ngOnInit() {
this.title = "Expense Entry"
}
}
Here,
app-expense-entry is the selector value and it can be used as regular HTML Tag.
Include bootstrap
Let us include bootstrap into our ExpenseManager application using styles option and
change the default template to use bootstrap components.
176
Angular 8
cd /go/to/expense-manager
Here,
We have installed JQuery because, bootstrap uses jquery extensively for advanced
components.
{
"projects": {
"expense-manager": {
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/expense-manager",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"./node_modules/bootstrap/dist/css/bootstrap.css",
"src/styles.css"
],
"scripts": [
"./node_modules/jquery/dist/jquery.js",
"./node_modules/bootstrap/dist/js/bootstrap.js"
]
},
},
}
}},
"defaultProject": "expense-manager"
}
Here,
177
Angular 8
<app-expense-entry></app-expense-entry>
Here,
178
Angular 8
</div>
</div>
<div class="container box" style="margin-top: 10px;">
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Item:</em></strong>
</div>
<div class="col" style="text-align: left;">
Pizza
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Amount:</em></strong>
</div>
<div class="col" style="text-align: left;">
20
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Category:</em></strong>
</div>
<div class="col" style="text-align: left;">
Food
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Location:</em></strong>
</div>
<div class="col" style="text-align: left;">
Zomato
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Spend On:</em></strong>
</div>
<div class="col" style="text-align: left;">
June 20, 2020
</div>
</div>
</div>
</div>
</div>
</div>
179
Angular 8
Add an interface
Create ExpenseEntry interface (src/app/expense-entry.ts) and add id, amount,
category, Location, spendOn and createdOn.
ngOnInit() {
this.title = "Expense Entry";
this.expenseEntry = {
180
Angular 8
id: 1,
item: "Pizza",
amount: 21,
category: "Food",
location: "Zomato",
spendOn: new Date(2020, 6, 1, 10, 10, 10),
createdOn: new Date(2020, 6, 1, 10, 10, 10),
};
}
}
181
Angular 8
{{ expenseEntry.category }}
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Location:</em></strong>
</div>
<div class="col" style="text-align: left;">
{{ expenseEntry.location }}
</div>
</div>
<div class="row">
<div class="col-2" style="text-align: right;">
<strong><em>Spend On:</em></strong>
</div>
<div class="col" style="text-align: left;">
{{ expenseEntry.spendOn }}
</div>
</div>
</div>
</div>
</div>
</div>
Using directives
Let us add a new component in our ExpenseManager application to list the expense
entries.
182
Angular 8
cd /go/to/expense-manager
ng serve
Output
Here, the command creates the ExpenseEntryList Component and update the necessary
code in AppModule.
getExpenseEntries() : ExpenseEntry[] {
let mockExpenseEntries : ExpenseEntry[] = [
{ id: 1,
item: "Pizza",
amount: Math.floor((Math.random() * 10) + 1),
category: "Food",
location: "Mcdonald",
spendOn: new Date(2020, 4, Math.floor((Math.random() *
30) + 1), 10, 10, 10),
createdOn: new Date(2020, 4, Math.floor((Math.random()
* 30) + 1), 10, 10, 10) },
{ id: 1,
item: "Pizza",
amount: Math.floor((Math.random() * 10) + 1),
category: "Food",
location: "KFC",
spendOn: new Date(2020, 4, Math.floor((Math.random() *
183
Angular 8
{ id: 1,
item: "Pizza",
amount: Math.floor((Math.random() * 10) + 1),
category: "Food",
location: "Mcdonald",
spendOn: new Date(2020, 4, Math.floor((Math.random() *
30) + 1), 10, 10, 10),
createdOn: new Date(2020, 4, Math.floor((Math.random()
* 30) + 1), 10, 10, 10) },
{ id: 1,
item: "Pizza",
amount: Math.floor((Math.random() * 10) + 1),
category: "Food",
location: "KFC",
spendOn: new Date(2020, 4, Math.floor((Math.random() *
30) + 1), 10, 10, 10),
createdOn: new Date(2020, 4, Math.floor((Math.random()
* 30) + 1), 10, 10, 10) },
{ id: 1,
item: "Pizza",
amount: Math.floor((Math.random() * 10) + 1),
category: "Food",
location: "KFC",
spendOn: new Date(2020, 4, Math.floor((Math.random() *
30) + 1), 10, 10, 10),
createdOn: new Date(2020, 4, Math.floor((Math.random()
* 30) + 1), 10, 10, 10) },
];
return mockExpenseEntries;
}
Declare a local variable, expenseEntries and load the mock list of expense entries as
mentioned below:
title: string;
expenseEntries: ExpenseEntry[];
constructor() { }
ngOnInit() {
this.title = "Expense Entry List";
this.expenseEntries = this.getExpenseEntries();
}
184
Angular 8
Here,
Used bootstrap table. table and table-striped will style the table according to
Boostrap style standard.
Used ngFor to loop over the expenseEntries and generate table rows.
185
Angular 8
...
<app-expense-entry-list></app-expense-entry-list>
Use pipes
Let us use the pipe in the our ExpenseManager application.
Here, we have used the date pipe to show the spend on date in the short format.
186
Angular 8
ng g service debug
This will create two Typescript files (debug service & its test) as specified below:
@Injectable({
providedIn: 'root'
})
export class DebugService {
constructor() { }
}
Here,
187
Angular 8
Let us add a method, Info, which will print the message into the browser console.
@Component({
selector: 'app-expense-entry-list',
templateUrl: './expense-entry-list.component.html',
styleUrls: ['./expense-entry-list.component.css']
})
export class ExpenseEntryListComponent implements OnInit {
title: string;
expenseEntries: ExpenseEntry[];
constructor(private debugService: DebugService) { }
ngOnInit() {
this.debugService.info("Expense Entry List component initialized");
this.title = "Expense Entry List";
this.expenseEntries = this.getExpenseEntries();
}
// other coding
}
Here,
The result can be viewed using developer tools and it looks similar as shown below:
188
Angular 8
// src/app/debug.service.ts
import { Injectable } from '@angular/core';
@Injectable()
export class DebugService {
constructor() {
}
189
Angular 8
// src/app/expense-entry-list/expense-entry-list.component.ts
@Component({
selector: 'app-expense-entry-list',
templateUrl: './expense-entry-list.component.html',
styleUrls: ['./expense-entry-list.component.css']
providers: [DebugService]
})
Here, we have used providers meta data (ElementInjector) to register the service.
@Component({
selector: 'app-debug',
templateUrl: './debug.component.html',
styleUrls: ['./debug.component.css']
})
export class DebugComponent implements OnInit {
ngOnInit() {
this.debugService.info("Debug component gets service from Parent");
}
}
Here, we have not registered DebugService. So, DebugService will not be available if
used as parent component. When used inside a parent component, the service may
available from parent, if the parent has access to the service.
// existing content
<app-debug></app-debug>
<ng-content></ng-content>
// navigation code
<app-expense-entry-list>
<app-debug></app-debug>
</app-expense-entry-list>
190
Angular 8
Let us check the application and it will show DebugService template at the end of the
page as shown below:
Also, we could able to see two debug information from debug component in the console.
This indicate that the debug component gets the service from its parent component.
Let us change how the service is injected in the ExpenseEntryListComponent and how
it affects the scope of the service. Change providers injector to viewProviders injection.
viewProviders does not inject the service into the content child and so, it should fail.
viewProviders: [DebugService]
Check the application and you will see that the one of the debug component (used as
content child) throws error as shown below.
191
Angular 8
Let us remove the debug component in the templates and restore the application.
<app-debug></app-debug>
<ng-content></ng-content>
// navigation code
<app-expense-entry-list> </app-expense-entry-list>
providers: [DebugService]
ExpenseEntryService will get the latest expense entries, insert new expense entries,
modify existing expense entries and delete the unwanted expense entries.
This will create two Typescript files (expense entry service & its test) as specified below:
192
Angular 8
...
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
...
HttpClientModule
...
]
...
...
})
export class AppModule { }
Create a variable, httpOptions to set the Http Header option. This will be used during the
Http Rest API call by Angular HttpClient service.
private httpOptions = {
headers: new HttpHeaders( { 'Content-Type': 'application/json' })
};
193
Angular 8
@Injectable({
providedIn: 'root'
})
export class ExpenseEntryService {
private expenseRestUrl = 'api/expense';
private httpOptions = {
headers: new HttpHeaders( { 'Content-Type': 'application/json'
})
};
constructor(
private httpClient : HttpClient) { }
}
cd /go/to/expense-rest-api
node .\server.js
getExpenseEntries() : Observable<ExpenseEntry[]> {
return this.httpClient.get<ExpenseEntry[]>(this.expenseRestUrl,
this.httpOptions)
.pipe(
retry(3),
catchError(this.httpErrorHandler)
);
}
194
Angular 8
error.message);
} else {
console.error(
"An error happened in server. The HTTP status code is " +
error.status + " and the error returned is " + error.message);
}
Here,
getExpenseEntries() calls the get() method using expense end point and also
configures the error handler. Also, it configures httpClient to try for maximum of
3 times in case of failure. Finally, it returns the response from server as typed
(ExpenseEntry[]) Observable object.
getExpenseEntry is similar to getExpenseEntries() except it passes the id of
the ExpenseEntry object and gets ExpenseEntry Observable object.
@Injectable({
providedIn: 'root'
})
export class ExpenseEntryService {
private expenseRestUrl = 'http://localhost:8000/api/expense';
private httpOptions = {
headers: new HttpHeaders( { 'Content-Type': 'application/json'
})
};
getExpenseEntries() : Observable<ExpenseEntry[]> {
return this.httpClient.get<ExpenseEntry[]>(this.expenseRestUrl,
this.httpOptions)
.pipe(
retry(3),
catchError(this.httpErrorHandler)
);
}
195
Angular 8
getExpenseItems() {
this.restService.getExpenseEntries()
.subscribe( data => this.expenseEntries = data );
}
@Component({
selector: 'app-expense-entry-list',
templateUrl: './expense-entry-list.component.html',
styleUrls: ['./expense-entry-list.component.css'],
providers: [DebugService]
})
export class ExpenseEntryListComponent implements OnInit {
title: string;
196
Angular 8
expenseEntries: ExpenseEntry[];
constructor(private debugService: DebugService, private restService :
ExpenseEntryService ) { }
ngOnInit() {
this.debugService.info("Expense Entry List component initialized");
this.title = "Expense Entry List";
this.getExpenseItems();
}
getExpenseItems() {
this.restService.getExpenseEntries()
.subscribe( data => this.expenseEntries = data );
}
}
Finally, check the application and you will see the below response:
197
Angular 8
catchError(this.httpErrorHandler)
);
}
Add Routing
Generate routing module using below command, if not done before.
Output
Here,
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Here, we have added route for our expense list and expense details component.
199
Angular 8
</div>
</nav>
<router-outlet></router-outlet>
Here, we have updated the expense list table and added a new column to show the view
option.
this.expenseEntry$ = this.route.paramMap.pipe(
switchMap(params => {
this.selectedId = Number(params.get('id'));
return
this.restService.getExpenseEntry(this.selectedId);
}));
200
Angular 8
goToList() {
this.router.navigate(['/expenses']);
}
@Component({
selector: 'app-expense-entry',
templateUrl: './expense-entry.component.html',
styleUrls: ['./expense-entry.component.css']
})
export class ExpenseEntryComponent implements OnInit {
title: string;
expenseEntry$ : Observable<ExpenseEntry>;
expenseEntry: ExpenseEntry = {} as ExpenseEntry;
selectedId: number;
ngOnInit() {
this.title = "Expense Entry";
this.expenseEntry$ = this.route.paramMap.pipe(
switchMap(params => {
this.selectedId = Number(params.get('id'));
return
this.restService.getExpenseEntry(this.selectedId);
}));
goToList() {
this.router.navigate(['/expenses']);
}
}
201
Angular 8
List</button>
<button type="button" class="btn btn-primary">Edit</button>
</div>
Clicking the view option of the first entry will navigate to details page and show the
selected expense entry as shown below:
202
Angular 8
@Injectable({
providedIn: 'root'
})
export class AuthService {
return of(this.isUserLoggedIn).pipe(
delay(1000),
tap(val => {
console.log("Is User Authentication is successful: " +
val);
})
);
}
logout(): void {
this.isUserLoggedIn = false;
localStorage.removeItem('isUserLoggedIn');
}
constructor() { }
}
Here,
203
Angular 8
Authentication validation is that the user name and password should be admin.
We have not used any backend. Instead we have simulated a delay of 1s using
Observables.
The purpose of the logout method is to invalidate the user and removes the
information stored in localStorage.
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
userName: string;
password: string;
formData: FormGroup;
ngOnInit() {
this.formData = new FormGroup({
userName: new FormControl("admin"),
password: new FormControl("admin"),
});
}
onClickSubmit(data: any) {
this.userName = data.userName;
this.password = data.password;
204
Angular 8
this.authService.login(this.userName, this.password)
.subscribe( data => {
console.log("Is Login Success: " + data);
if(data) this.router.navigate(['/expenses']);
});
}
}
Here,
205
Angular 8
</div>
</div>
</div>
</div>
</div>
</div>
Here,
.form-signin {
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
input {
margin-bottom: 20px;
}
@Component({
selector: 'app-logout',
templateUrl: './logout.component.html',
styleUrls: ['./logout.component.css']
})
export class LogoutComponent implements OnInit {
206
Angular 8
{ }
ngOnInit() {
this.authService.logout();
this.router.navigate(['/']);
}
Here,
@Injectable({
providedIn: 'root'
})
export class ExpenseGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean | UrlTree {
let url: string = state.url;
return this.checkLogin(url);
}
207
Angular 8
this.router.parseUrl('/expenses');
else
return true;
} else {
return this.router.parseUrl('/login');
}
}
}
Here,
checkLogin will check whether the localStorage has the user information and if it
is available, then it returns true.
If the user is logged in and goes to login page, it will redirect the user to expenses
page.
If the user is not logged in, then the user will be redirected to login page.
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Here,
208
Angular 8
Created two new routes, login and logout to access LoginComponent and
LogoutComponent respectively.
Add new option canActivate for ExpenseEntryComponent and
ExpenseEntryListComponent.
Open AppComponent template and add two login and logout link.
<ng-template #isLogOut>
<a class="nav-link"
routerLink="/login">Login</a>
</ng-template>
</li>
</ul>
</div>
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
209
Angular 8
isUserLoggedIn = false;
ngOnInit() {
let storeData = localStorage.getItem("isUserLoggedIn");
console.log("StoreData: " + storeData);
Here, we have added the logic to identify the user status so that we can show login /
logout functionality.
imports: [
ReactiveFormsModule
]
Now, run the application and the application opens the login page.
210
Angular 8
Enter admin and admin as username and password and then click submit. The application
process the login and redirects the user to expense list page as shown below:
211
Angular 8
@Component({
selector: 'app-edit-entry',
templateUrl: './edit-entry.component.html',
styleUrls: ['./edit-entry.component.css']
})
export class EditEntryComponent implements OnInit {
id: number;
item: string;
amount: number;
category: string;
location: string;
spendOn: Date;
formData: FormGroup;
selectedId: number;
expenseEntry: ExpenseEntry;
ngOnInit() {
this.formData = new FormGroup({
id: new FormControl(),
item: new FormControl('', [Validators.required]),
amount: new FormControl('', [Validators.required]),
category: new FormControl(),
location: new FormControl(),
spendOn: new FormControl()
});
this.selectedId =
Number(this.route.snapshot.paramMap.get('id'));
this.expenseEntryService.getExpenseEntry(this.selectedId)
.subscribe( (data) =>
{
this.expenseEntry = data;
this.formData.controls['id'].setValue(this.expenseEntry.id);
this.formData.controls['item'].setValue(this.expenseEntry.item);
this.formData.controls['amount'].setValue(this.expenseEntry.amount);
this.formData.controls['category'].setValue(this.expenseEntry.category);
this.formData.controls['location'].setValue(this.expenseEntry.location);
212
Angular 8
this.formData.controls['spendOn'].setValue(this.expenseEntry.spendOn);
})
}
get itemValue() {
return this.formData.get('item');
}
get amountValue() {
return this.formData.get('amount');
}
onClickSubmit(data: any) {
console.log('onClickSubmit fired');
this.id = data.id;
this.item = data.item;
this.amount = data.amount;
this.category = data.category;
this.location = data.location;
this.spendOn = data.spendOn;
Here,
213
Angular 8
214
Angular 8
<option>Bill</option>
</select>
</div>
<div class="form-group">
<label for="location">location</label>
<input type="text" class="form-control" id="location"
formControlName="location">
</div>
<div class="form-group">
<label for="spendOn">spendOn</label>
<input type="text" class="form-control" id="spendOn"
formControlName="spendOn">
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit"
[disabled]="!formData.valid">Submit</button>
</form>
</div>
</div>
</div>
</div>
Here,
Created a form and bind it to the form, formData created in the class.
Validated item and amount as required values.
Called onClickSubmit function once validation in successful.
.form {
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
.form label {
text-align: left;
width: 100%;
}
input {
margin-bottom: 20px;
}
215
Angular 8
@Component({
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.css']
})
export class AboutComponent implements OnInit {
title = "About";
constructor() { }
ngOnInit() {
}
Add routing for add and edit expense entries as specified below:
216
Angular 8
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Here, we have added about, add expense and edit expense routes.
217
Angular 8
Here, we have included two more columns. One column is used to show edit link and
another to show delete link.
deleteExpenseEntry(evt, id) {
evt.preventDefault();
if(confirm("Are you sure to delete the entry?")) {
this.restService.deleteExpenseEntry(id)
.subscribe( data => console.log(data) );
this.getExpenseItems();
}
}
Here, we have asked to confirm the deletion and it user confirmed, called the
deleteExpenseEntry method from expense service to delete the selected expense item.
Change Edit link in the ExpenseEntryListComponent template at the top to Add link
as shown below:
218
Angular 8
goToEdit() {
this.router.navigate(['/expenses/edit', this.selectedId]);
}
<ng-template #isLogOut>
<a class="nav-link"
routerLink="/login">Login</a>
</ng-template>
</li>
</ul>
</div>
</div>
</nav>
<router-outlet></router-outlet>
Here, we have updated the add expense link and about link.
Run the application and the output will be similar as shown below:
219
Angular 8
Try to add new expense using Add link in expense list page. The output will be similar as
shown below:
220
Angular 8
If the data is not filled properly, the validation code will alert as shown below:
Click Submit. It will trigger the submit event and the data will be saved to the backend
and redirected to list page as shown below:
221
Angular 8
Try to edit existing expense using Edit link in expense list page. The output will be
similar as shown below:
Click Submit. It will trigger the submit event and the data will be saved to the backend
and redirected to list page.
To delete an item, click delete link. It will confirm the deletion as shown below:
222
Angular 8
223
29. Angular 9 ― What’s New? Angular 8
Angular community has continuosly updating its version. This chapter explains about
Angular 9 version updates.
Install Angular 9
If you want to work with Angular 9, first you need to setup Angular 9 CLI using the below
command:
After executing this command, you can check the version using the below command:
ng version
Angular 9 Updates
Let’s understand Angular 9 updates in brief.
Ivy compiler
Ivy compiler becomes the default compiler in Angular 9. This makes apps will be faster
and very efficient. Whereas, Angular 8 Ivy is optional. We have to enable it inside
tsconfig.json file.
Reliable ng update
ng updates are very reliable. It contains clear progress updates and runs all of the
migrations. This can be done using the below command:
224
Angular 8
ng update --create-commits
Here,
@Injectable service helps to add injector in your application. providedIn meta data
provides new option, platform to ensure the object can be used and shared by all
application. It is defined below:
@Injectable({
providedIn: 'platform'
})
class MyService {...}
TypeScript 3.8
Angular 9 is designed to support 3.8 version. TypeScript 3.8 brings support for the below
features:
Angular 9.0.0-next.5
Angular 9.0.0-next.5 build has small size of main.js file, which makes better performance
compare to previous version of Angular 8.
IDE enhancement
Angular 9 provides imporves IDE supports. TextMate grammar enables for syntax
highlighting in inline and external templates.
Conclusion
Angular is flexible, ever improving, continuously updated and dependable framework.
Angular greatly simplify the process of SPA development. By providing new features in
each release like Angular Universal, Progressive Web App, Web workers, Bazel
build, Ivy Compiler, etc., Angular will have a long life and complete support of the front
end developer.
225