Learning Angular 2
Learning Angular 2
#angular2
Table of Contents
About 1
Remarks 2
Versions 2
Examples 3
Prerequisites: 3
Step 1 6
Step 2 6
Step 3 8
Step 5 9
Step 6 9
Step 7 10
Step 8 10
What now? 11
Getting started with Angular 2 with node.js/expressjs backend (http example included) 12
Prerequisites 12
Roadmap 12
Step 1 12
Step2 13
Step3 14
Remarks 23
Examples 23
Examples 26
Examples 29
Syntax 32
Remarks 32
Examples 32
Angular 2 for-loop 32
Examples 35
Basic example 35
Remarks 37
Examples 37
Data driven form 37
Remarks 40
Examples 40
pw-change.template.html 40
pw-change.component.ts 41
pw-validators.ts 41
registration-form.component.ts 44
registration-form.html 44
Angular 2 Forms ( Reactive Forms ) with registration form and confirm password validation 45
app.module.ts 45
app.component.ts 45
app.component.html 46
validators.ts 46
Examples 49
Md2Select 49
Md2Tooltip 49
Md2Toast 49
Md2Datepicker 50
Examples 51
Basic 51
change state 52
Remarks 54
Examples 54
Basic request 54
Introduction 57
Examples 57
Basic Animation - Transitions an element between two states driven by a model attribute. 57
Examples 59
Angular2 CanActivate 59
Parameters 60
Examples 60
Examples 62
@Input() 62
Remarks 64
Examples 64
Basic Setup 64
Examples 67
Input() 67
Parent Component : Initialize users lists. 67
Introduction 69
Examples 69
Examples 70
Introduction 74
Examples 74
Requirements 76
Introduction 77
Examples 77
Examples 79
Chapter 23: Attribute directives to affect the value of properties on the host node by usi 81
Examples 81
@HostBinding 81
Chapter 24: Barrel 82
Introduction 82
Examples 82
Using Barrel 82
Examples 83
An empty module 83
Introduction 85
Remarks 85
Examples 85
Parameters 86
Remarks 86
SUPER IMPORTANT! 86
DISABLING SANITIZING LEAVES YOU AT RISK OF XSS (Cross-Site Scripting) AND OTHER ATTACK
VEC 86
Examples 86
Introduction 90
Examples 90
Location Class 90
AsyncPipe 90
Currency Pipe 91
Parameters 93
Examples 93
Introduction 98
Examples 98
Introduction 105
Examples 105
Chapter 32: Configuring ASP.net Core application to work with Angular 2 and TypeScript 109
Introduction 109
Examples 109
Introduction 115
Examples 115
.gitignore 115
.npmignore 115
gulpfile.js 115
index.d.ts 116
index.js 116
package.json 116
dist/tsconfig.json 117
src/angular-x-minimal-npm-package.component.ts 118
src/angular-x-minimal-npm-package.component.html 118
src/angular-x-data-table.component.css 118
src/angular-x-minimal-npm-package.module.ts 118
Publish 119
Introduction 120
Examples 120
Compilation 121
Syntax 125
Examples 125
Examples 127
Examples 130
Examples 132
Syntax 133
Remarks 133
Examples 133
*ngFor 134
Syntax 139
Examples 139
Examples 144
Dropzone 144
Examples 146
Examples 152
Chapter 44: Example for routes such as /route/subroute for static urls 154
Examples 154
Examples 155
Introduction 156
Examples 156
Introduction 158
Syntax 158
Examples 158
To run a function at the start or end of *ngFor loop Using *ngIf 159
Examples 161
Remarks 164
Examples 164
Add 3rd party library that does not have typings 166
Examples 168
Remarks 170
Examples 170
OnInit 170
OnDestroy 171
OnChanges 171
AfterContentInit 171
AfterContentChecked 172
AfterViewInit 172
AfterViewChecked 172
DoCheck 173
Introduction 174
Parameters 174
Remarks 174
Examples 174
Introduction 183
Examples 183
Introduction 185
Examples 185
5) Import our UserReducer into our main module to build the Store 188
6) Use data from the Store to display information in our view 189
Examples 192
Introduction 194
Examples 194
Introduction 197
Syntax 197
Examples 197
Introduction 198
Parameters 198
Remarks 198
Examples 198
Example 200
hotel-reservation.component.ts 200
hotel-reservation.template.html 200
Output 200
Code 200
Output 201
Examples 207
ResolveData 210
Remarks 215
Examples 215
Bootstrapping 215
Introduction 223
Examples 223
Examples 226
Introduction 231
Examples 231
Examples 233
Installing the Jasmine testing framework 233
Install 233
Verify 233
Introduction 242
Examples 242
Examples 244
Examples 246
Remarks 247
Examples 247
Chapter 69: Using third party libraries like jQuery in Angular 2 248
Introduction 248
Examples 248
NPM 248
Note 248
Using NgZone to do multiple HTTP requests before showing the data 250
Credits 252
About
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: angular-2
It is an unofficial and free Angular 2 ebook created for educational purposes. All the content is
extracted from Stack Overflow Documentation, which is written by many hardworking individuals at
Stack Overflow. It is neither affiliated with Stack Overflow nor official Angular 2.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/ 1
Chapter 1: Getting started with Angular 2
Remarks
This section provides an overview of how to install and configure Angular2+ for use in various
environments and IDE's using tools like the community developed angular-cli.
The previous version of Angular is AngularJS or also named Angular 1. See here the
documentation.
Versions
4.3.3 2017-08-02
4.3.2 2017-07-26
4.3.1 2017-07-19
4.3.0 2017-07-14
4.2.0 2017-06-08
4.1.0 2017-04-26
4.0.0 2017-03-23
2.3.0 2016-12-08
2.2.0 2016-11-14
2.1.0 2016-10-13
2.0.2 2016-10-05
2.0.1 2016-09-23
2.0.0 2016-09-14
2.0.0-rc.7 2016-09-13
2.0.0-rc.6 2016-08-31
2.0.0-rc.5 2016-08-09
2.0.0-rc.4 2016-06-30
https://riptutorial.com/ 2
Version Release Date
2.0.0-rc.3 2016-06-21
2.0.0-rc.2 2016-06-15
2.0.0-rc.1 2016-05-03
2.0.0-rc.0 2016-05-02
Examples
Install angular2 with angular-cli
This example is a quick setup of Angular 2 and how to generate a quick example project.
Prerequisites:
• Node.js v4 or greater.
• npm v3 or greater or yarn.
or
The previous command installs @angular/cli globally, adding the executable ng to PATH.
ng new PROJECT_NAME
cd PROJECT_NAME
ng serve
That is it, you now have a simple example project made with Angular 2. You can now navigate to
the link displayed in terminal and see what it is running.
https://riptutorial.com/ 3
To add to an existing project
Navigate to the root of your current project.
ng init
This will add the necessary scaffolding to your project. The files will be created in the current
directory so be sure to run this in an empty directory.
ng serve
If the server started successfully it should display an address at which the server is running.
Usually is this:
http://localhost:4200
Out of the box this local development server is hooked up with Hot Module Reloading, so any
changes to the html, typescript, or css, will trigger the browser to be automatically reloaded (but
can be disabled if desired).
# The command below will generate a component in the folder you are currently at
ng generate component my-generated-component
# Using the alias (same outcome as above)
ng g component my-generated-component
https://riptutorial.com/ 4
Scaffold Type Usage
You can also replace the type name by its first letter. For example:
Building/Bundling
When you are all finished building your Angular 2 web app and you would like to install it on a web
server like Apache Tomcat, all you need to do is run the build command either with or without the
production flag set. Production will minifiy the code and optimize for a production setting.
ng build
or
ng build --prod
Then look in the projects root directory for a /dist folder, which contains the build.
If you'd like the benefits of a smaller production bundle, you can also use Ahead-of-Time template
compilation, which removes the template compiler from the final build:
Unit Testing
Angular 2 provides built-in unit testing, and every item created by angular-cli generates a basic
unit test, that can be expanded. The unit tests are written using jasmine, and executed through
Karma. In order to start testing execute the following command:
ng test
This command will execute all the tests in the project, and will re-execute them every time a
source file changes, whether it is a test or code from the application.
https://riptutorial.com/ 5
For more info also visit: angular-cli github page
Angular 2.0.0-rc.4
In this example we'll create a "Hello World!" app with only one root component (AppComponent) for
the sake of simplicity.
Prerequisites:
• Node.js v5 or later
• npm v3 or later
Note: You can check versions by running node -v and npm -v in the console/terminal.
Step 1
Create and enter a new folder for your project. Let's call it angular2-example.
mkdir angular2-example
cd angular2-example
Step 2
Before we start writing our app code, we'll add the 4 files provided below: package.json,
tsconfig.json, typings.json, and systemjs.config.js.
Disclaimer: The same files can be found in the Official 5 Minute Quickstart.
package.json - Allows us to download all dependencies with npm and provides simple script
execution to make life easier for simple projects. (You should consider using something like Gulp
in the future to automate tasks).
{
"name": "angular2-example",
"version": "1.0.0",
"scripts": {
"start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
"lite": "lite-server",
"postinstall": "typings install",
"tsc": "tsc",
"tsc:w": "tsc -w",
"typings": "typings"
},
"license": "ISC",
"dependencies": {
"@angular/common": "2.0.0-rc.4",
"@angular/compiler": "2.0.0-rc.4",
"@angular/core": "2.0.0-rc.4",
"@angular/forms": "0.2.0",
https://riptutorial.com/ 6
"@angular/http": "2.0.0-rc.4",
"@angular/platform-browser": "2.0.0-rc.4",
"@angular/platform-browser-dynamic": "2.0.0-rc.4",
"@angular/router": "3.0.0-beta.1",
"@angular/router-deprecated": "2.0.0-rc.2",
"@angular/upgrade": "2.0.0-rc.4",
"systemjs": "0.19.27",
"core-js": "^2.4.0",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"zone.js": "^0.6.12",
"angular2-in-memory-web-api": "0.0.14",
"bootstrap": "^3.3.6"
},
"devDependencies": {
"concurrently": "^2.0.0",
"lite-server": "^2.2.0",
"typescript": "^1.8.10",
"typings":"^1.0.4"
}
}
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
}
}
{
"globalDependencies": {
"core-js": "registry:dt/core-js#0.0.0+20160602141332",
"jasmine": "registry:dt/jasmine#2.2.0+20160621224255",
"node": "registry:dt/node#6.0.0+20160621231320"
}
}
/**
* System configuration for Angular 2 samples
* Adjust as necessary for your application's needs.
*/
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': 'app', // 'dist',
https://riptutorial.com/ 7
'@angular': 'node_modules/@angular',
'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
'rxjs': 'node_modules/rxjs'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
};
var ngPackageNames = [
'common',
'compiler',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'router',
'router-deprecated',
'upgrade',
];
// Individual files (~300 requests):
function packIndex(pkgName) {
packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
}
// Bundled (~40 requests):
function packUmd(pkgName) {
packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js',
defaultExtension: 'js' };
}
// Most environments should use UMD; some (Karma) need the individual index files
var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
// Add package entries for angular packages
ngPackageNames.forEach(setPackageConfig);
var config = {
map: map,
packages: packages
};
System.config(config);
})(this);
Step 3
Let's install the dependencies by typing
npm install
in the console/terminal.
Step 4
<html>
<head>
https://riptutorial.com/ 8
<title>Angular2 example</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app></my-app>
</body>
</html>
However, Angular still doesn't know what to render. To tell it that, we'll define AppComponent.
Step 5
Create a subfolder called app where we can define the components and services that make up our
app. (In this case, it'll just contain the AppComponent code and main.ts.)
mkdir app
Step 6
Create the file app/app.component.ts
@Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<ul>
<li *ngFor="let message of messages">
{{message}}
</li>
</ul>
`
})
export class AppComponent {
title = "Angular2 example";
messages = [
"Hello World!",
"Another string",
"Another one"
https://riptutorial.com/ 9
];
}
What's happening? First, we're importing the @Component decorator which we use to give Angular
the HTML tag and template for this component. Then, we're creating the class AppComponent with
title and messages variables that we can use in the template.
<h1>{{title}}</h1>
<ul>
<li *ngFor="let message of messages">
{{message}}
</li>
</ul>
We're displaying the title variable in an h1 tag and then making a list showing each element of the
messages array by using the *ngFor directive. For each element in the array, *ngFor creates a message
variable that we use within the li element. The result will be:
<h1>Angular 2 example</h1>
<ul>
<li>Hello World!</li>
<li>Another string</li>
<li>Another one</li>
</ul>
Step 7
Now we create a main.ts file, which will be the first file that Angular looks at.
bootstrap(AppComponent);
We're importing the bootstrap function and AppComponent class, then using bootstrap to tell Angular
which component to use as the root.
Step 8
It's time to fire up your first app. Type
npm start
in your console/terminal. This will run a prepared script from package.json that starts lite-server,
opens your app in a browser window, and runs the TypeScript transpiler in watch mode (so .ts
https://riptutorial.com/ 10
files will be transpiled and the browser will refresh when you save changes).
What now?
Check out the official Angular 2 guide and the other topics on StackOverflow's documentation.
You can also edit AppComponent to use external templates, styles or add/edit component variables.
You should see your changes immediately after saving files.
Step 1: Locate your download of Node.js, typically it is installed under C:/program files/nodejs
Step 3: In the options window navigate to "Projects and Solutions>External Web Tools"
Step 4: Add new entry with you Node.js file location (C:/program files/nodejs), IMPORTANT use
the arrow buttons on menu to move your reference to the top of the list.
Step 5: Restart Visual Studios and Run an npm install, against your project, from npm command
window
If you are attempting to get an Angular2 site running on your Windows work computer at XYZ
https://riptutorial.com/ 11
MegaCorp the chances are that you are having problems getting through the company proxy.
There are (at least) two package managers that need to get through the proxy:
1. NPM
2. Typings
For NPM you need to add the following lines to the .npmrc file:
proxy=http://[DOMAIN]%5C[USER]:[PASS]@[PROXY]:[PROXYPORT]/
https-proxy=http://[DOMAIN]%5C[USER]:[PASS]@[PROXY]:[PROXYPORT]/
For Typings you need to add the following lines to the .typingsrc file:
proxy=http://[DOMAIN]%5C[USER]:[PASS]@[PROXY]:[PROXYPORT]/
https-proxy=http://[DOMAIN]%5C[USER]:[PASS]@[PROXY]:[PROXYPORT]/
rejectUnauthorized=false
These files probably don't exist yet, so you can create them as blank text files. They can be added
to the project root (same place as package.json or you can put them in %HOMEPATH% and they will be
available to all your projects.
The bit that isn't obvious and is the main reason people think the proxy settings aren't working is
the %5C which is the URL encode of the \ to separate the domain and user names. Thanks to
Steve Roberts for that one: Using npm behind corporate proxy .pac
We will create a simple "Hello World!" app with Angular2 2.4.1 (@NgModule change) with a node.js
(expressjs) backend.
Prerequisites
• Node.js v4.x.x or higher
• npm v3.x.x or higher or yarn
Then run npm install -g typescript or yarn global add typescriptto install typescript globally
Roadmap
Step 1
Create a new folder (and the root dir of our back-end) for our app. Let's call it Angular2-express.
command line:
https://riptutorial.com/ 12
mkdir Angular2-express
cd Angular2-express
Step2
Create the package.json (for dependencies) and app.js (for bootstrapping) for our node.js app.
package.json:
{
"name": "Angular2-express",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "node app.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.13.3",
"express": "^4.13.3"
}
}
app.js:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}) );
//send the index.html on every page refresh and let angular handle the routing
app.get('/*', function(req, res, next) {
console.log("Reloading");
res.sendFile('index.html', { root: __dirname });
});
https://riptutorial.com/ 13
Step3
Our front-end should be in a folder named front inside our Angular2-express folder.
command line:
mkdir front
cd front
Just like we did with our back-end our front-end needs the dependency files too. Let's go ahead
and create the following files: package.json, systemjs.config.js, tsconfig.json
package.json:
{
"name": "Angular2-express",
"version": "1.0.0",
"scripts": {
"tsc": "tsc",
"tsc:w": "tsc -w"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/angular/angular.io/blob/master/LICENSE"
}
],
"dependencies": {
"@angular/common": "~2.4.1",
"@angular/compiler": "~2.4.1",
"@angular/compiler-cli": "^2.4.1",
"@angular/core": "~2.4.1",
"@angular/forms": "~2.4.1",
"@angular/http": "~2.4.1",
"@angular/platform-browser": "~2.4.1",
"@angular/platform-browser-dynamic": "~2.4.1",
"@angular/platform-server": "^2.4.1",
"@angular/router": "~3.4.0",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.8",
"rxjs": "^5.0.2",
"systemjs": "0.19.40",
"zone.js": "^0.7.4"
},
"devDependencies": {
"@types/core-js": "^0.9.34",
"@types/node": "^6.0.45",
"typescript": "2.0.2"
}
}
systemjs.config.js:
/**
* System configuration for Angular samples
* Adjust as necessary for your application needs.
https://riptutorial.com/ 14
*/
(function (global) {
System.config({
defaultJSExtensions:true,
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-
browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-
dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api',
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
}
}
});
})(this);
tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"compileOnSave": true,
"exclude": [
"node_modules/*"
]
}
https://riptutorial.com/ 15
Then run an npm install or yarn to install the dependencies.
Now that our dependency files are complete. Let's move on to our index.html:
index.html:
<html>
<head>
<base href="/">
<title>Angular2-express</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
</body>
</html>
Now we're ready to create our first component. Create a folder named app inside our front folder.
command line:
mkdir app
cd app
main.ts:
app.module.ts:
https://riptutorial.com/ 16
import { AppComponent } from './app.component';
@NgModule({
imports: [
BrowserModule,
HttpModule
],
declarations: [
AppComponent
],
providers:[ ],
bootstrap: [ AppComponent ]
})
export class AppModule {}
app.component.ts:
@Component({
selector: 'my-app',
template: 'Hello World!',
providers: []
})
export class AppComponent {
constructor(private http: Http){
//http get example
this.http.get('/test')
.subscribe((res)=>{
console.log(res);
});
}
}
After this, compile the typescript files to javascript files. Go 2 levels up from the current dir (inside
Angular2-express folder) and run the command below.
command line:
cd ..
cd ..
tsc -p front
Angular2-express
├── app.js
├── node_modules
├── package.json
├── front
│ ├── package.json
│ ├── index.html
│ ├── node_modules
│ ├── systemjs.config.js
│ ├── tsconfig.json
│ ├── app
https://riptutorial.com/ 17
│ │ ├── app.component.ts
│ │ ├── app.component.js.map
│ │ ├── app.component.js
│ │ ├── app.module.ts
│ │ ├── app.module.js.map
│ │ ├── app.module.js
│ │ ├── main.ts
│ │ ├── main.js.map
│ │ ├── main.js
Finally, inside Angular2-express folder, run node app.js command in the command line. Open your
favorite browser and check localhost:9999 to see your app.
Angular 4 is now available! Actually Angular uses semver since Angular 2, which requires the
major number being increased when breaking changes were introduced. The Angular team
postponed features that cause breaking changes, which will be released with Angular 4. Angular 3
was skipped to be able to align the version numbers of the core modules, because the Router
already had version 3.
As per the Angular team, Angular 4 applications are going to be less space consuming and faster
than before. They have separated animation package from @angular/core package. If anybody is
not using animation package so extra space of code will not end up in the production. The
template binding syntax now supports if/else style syntax. Angular 4 is now compatible with most
recent version of Typescript 2.1 and 2.2. So, Angular 4 is going to be more exciting.
You can use Angular-CLI (Command Line Interface) , It will install all dependencies for you.
• You can use github and clone the Angular4-boilerplate. (It is the easiest one. )
Before You start using Angular-CLI , make sure You have node installed in your machine. Here, I
am using node v7.8.0. Now, Open your terminal and type the following command for Angular-CLI.
or
https://riptutorial.com/ 18
Let’s install Angular 4 using Angular-CLI.
ng new Angular4-boilerplate
cd Angular4-boilerplate We are all set for Angular 4. Its pretty easy and straightforward method.
Now Let’s see the second approach. I ll show you how to migrate Angular 2 to Angular 4. For that
You need clone any Angular 2 project and update Angular 2 dependencies with the Angular 4
Dependency in your package.json as following:
"dependencies": {
"@angular/animations": "^4.1.0",
"@angular/common": "4.0.2",
"@angular/compiler": "4.0.2",
"@angular/core": "^4.0.1",
"@angular/forms": "4.0.2",
"@angular/http": "4.0.2",
"@angular/material": "^2.0.0-beta.3",
"@angular/platform-browser": "4.0.2",
"@angular/platform-browser-dynamic": "4.0.2",
"@angular/router": "4.0.2",
"typescript": "2.2.2"
}
These are the main dependencies for Angular 4. Now You can npm install and then npm start to
run the application. For reference my package.json.
Before starting this step make sure you have git installed in your machine. Open your terminal and
clone the angular4-boilerplate using below command:
[email protected]:CypherTree/angular4-boilerplate.git
npm install
npm start
And you are done with the Angular 4 setup. All the steps are very straightforward so you can opt
any of them.
Angular4-boilerplate
-karma
-node_modules
-src
-mocks
https://riptutorial.com/ 19
-models
-loginform.ts
-index.ts
-modules
-app
-app.component.ts
-app.component.html
-login
-login.component.ts
-login.component.html
-login.component.css
-widget
-widget.component.ts
-widget.component.html
-widget.component.css
........
-services
-login.service.ts
-rest.service.ts
-app.routing.module.ts
-app.module.ts
-bootstrap.ts
-index.html
-vendor.ts
-typings
-webpack
-package.json
-tsconfig.json
-tslint.json
-typings.json
model folder contains the class and interface that used in component.
modules folder contains list of components such as app, login, widget etc. All component contains
typescript, html and css file. index.ts is for exporting all the class.
services folder contains list of services used in application. I have separated rest service and
different component service. In rest service contains different http methods. Login service works
as mediator between login component and rest service.
https://riptutorial.com/ 20
karma contains karma configuration for unit test.
In login.component.ts
@Component({
selector: 'login',
template: require('./login.component.html'),
styles: [require('./login.component.css')]
})
export class LoginComponent {
https://riptutorial.com/ 21
}
];
In root component, app.module.ts file you just need to import that component.
.....
import { LoginComponent } from './modules';
......
@NgModule({
bootstrap: [AppComponent],
declarations: [
LoginComponent
.....
.....
]
.....
})
export class AppModule { }
and after that npm install and npm start. Here, you go! You can check login screen in your
localhost. In case of any difficulty, You can refer the angular4-boilerplate.
Basically I can feel less building package and more faster response with Angular 4 application and
Although I found Exactly similar to Angular 2 in coding.
https://riptutorial.com/ 22
Chapter 2: Advanced Component Examples
Remarks
Remember that Angular 2 is all about singular responsibility. No matter how small your component
is, dedicate a separate logic for each and every component. Be it a button, a fancy anchor link, a
dialog header or even a sidenav's sub item.
Examples
Image Picker with Preview
In this example, we are going to create an image picker that previews your picture before
uploading. The previewer also supports drag and dropping files into the input. In this example, I
am only going to cover uploading single files, but you can tinker a bit to get multi file upload
working.
image-preview.html
<!-- file input, accepts images only. Detect when file has been picked/changed with Angular's
native (change) event listener -->
<input type="file" accept="image/*" (change)="updateSource($event)">
<!-- img placeholder when a file has been picked. shows only when 'source' is not empty -->
<img *ngIf="source" [src]="source" src="">
image-preview.ts
import {
Component,
Output,
EventEmitter,
} from '@angular/core';
@Component({
selector: 'image-preview',
styleUrls: [ './image-preview.css' ],
templateUrl: './image-preview.html'
})
export class MtImagePreviewComponent {
// Emit an event when a file has been picked. Here we return the file itself
@Output() onChange: EventEmitter<File> = new EventEmitter<File>();
https://riptutorial.com/ 23
constructor() {}
// If the input has changed(file picked) we project the file into the img previewer
updateSource($event: Event) {
// We access he file with $event.target['files'][0]
this.projectImage($event.target['files'][0]);
}
another.component.html
<form (ngSubmit)="submitPhoto()">
<image-preview (onChange)="getFile($event)"></image-preview>
<button type="submit">Upload</button>
</form>
And that's it. Way more easier than it was in AngularJS 1.x. I actually made this component based
on an older version I made in AngularJS 1.5.5.
@Component({
selector: 'component',
template: `
<input [formControl]="control" />
<div *ngFor="let item of content">
{{item.id}} - {{item.name}}
</div>
`
})
export class MyComponent implements OnInit, OnDestroy {
https://riptutorial.com/ 24
private originalContent = [
{ id: 1, name: 'abc' },
{ id: 2, name: 'abce' },
{ id: 3, name: 'ced' }
];
public ngOnInit() {
this.subscription = this.control.valueChanges.subscribe(value => {
this.content = this.originalContent.filter(item => item.name.startsWith(value));
});
}
public ngOnDestroy() {
this.subscription.unsubscribe();
}
https://riptutorial.com/ 25
Chapter 3: Ahead-of-time (AOT) compilation
with Angular 2
Examples
1. Install Angular 2 dependencies with compiler
NOTE: for best results, make sure your project was created using the Angular-CLI.
You don't have to do this step if you project already has angular 2 and all of these dependencies
installed. Just make sure that the compiler is in there.
...
"angularCompilerOptions": {
"genDir": "./ngfactory"
}
...
from the root of your project ./node_modules/.bin/ngc -p src where src is where all your angular 2
code lives. This will generate a folder called ngfactory where all your compiled code will live.
At this point you should be able to run your project. In this case, my project was created using the
Angular-CLI.
https://riptutorial.com/ 26
> ng serve
Q. Why we need compilation? Ans. We need compilation for achieving higher level of efficiency of
our Angular applications.
// ...
compile: function (el, scope) {
var dirs = this._getElDirectives(el);
var dir;
var scopeCreated;
dirs.forEach(function (d) {
dir = Provider.get(d.name + Provider.DIRECTIVES_SUFFIX);
if (dir.scope && !scopeCreated) {
scope = scope.$new();
scopeCreated = true;
}
dir.link(el, scope, d.value);
});
Array.prototype.slice.call(el.children).forEach(function (c) {
this.compile(c, scope);
}, this);
},
// ...
<ul>
<li *ngFor="let name of names"></li>
</ul>
// ...
this._text_9 = this.renderer.createText(this._el_3, '\n', null);
this._text_10 = this.renderer.createText(parentRenderNode, '\n\n', null);
this._el_11 = this.renderer.createElement(parentRenderNode, 'ul', null);
this._text_12 = this.renderer.createText(this._el_11, '\n ', null);
this._anchor_13 = this.renderer.createTemplateAnchor(this._el_11, null);
this._appEl_13 = new import2.AppElement(13, 11, this, this._anchor_13);
this._TemplateRef_13_5 = new import17.TemplateRef_(this._appEl_13,
viewFactory_HomeComponent1);
this._NgFor_13_6 = new import15.NgFor(this._appEl_13.vcRef, this._TemplateRef_13_5,
this.parentInjector.get(import18.IterableDiffers), this.ref);
// ...
https://riptutorial.com/ 27
2. Compilation of the application with ngc.
3. Performs compilation of the templates with the Angular compiler to TypeScript.
4. Compilation of the TypeScript code to JavaScript.
5. Bundling.
6. Minification.
7. Deployment.
Although the above process seems lightly more complicated the user goes only through the steps:
As you can see the third step is missing which means faster/better UX and on top of that tools like
angular2-seed and angular-cli will automate the build process dramatically.
The Angular CLI command-line interface has AoT compilation support since beta 17.
https://riptutorial.com/ 28
Chapter 4: Angular 2 - Protractor
Examples
Testing Navbar routing with Protractor
First lets create basic navbar.html with 3 options. (Home, List , Create)
describe('Navbar', () => {
beforeEach(() => {
browser.get('home'); // before each test navigate to home page.
});
function checkNavbarTexts(){
element(by.id('home-navbar')).getText().then(function(text){ // Promise
expect(text).toEqual('Home');
});
element(by.id('list-navbar')).getText().then(function(text){ // Promise
expect(text).toEqual('List');
});
element(by.id('create-navbar')).getText().then(function(text){ // Promise
expect(text).toEqual('Create');
});
}
function navigateToListPage(){
element(by.id('list-home')).click().then(function(){ // first find list-home a tag and
than click
browser.sleep(2000).then(function(){
browser.getCurrentUrl().then(function(actualUrl){ // promise
https://riptutorial.com/ 29
expect(actualUrl.indexOf('list') !== -1).toBeTruthy(); // check the current url is
list
});
});
});
}
});
const config = {
baseUrl: 'http://localhost:3000/',
specs: [
'./dev/**/*.e2e-spec.js'
],
exclude: [],
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
isVerbose: false,
includeStackTrace: false
},
directConnect: true,
capabilities: {
browserName: 'chrome',
shardTestFiles: false,
chromeOptions: {
'args': ['--disable-web-security ','--no-sandbox', 'disable-extensions', 'start-
maximized', 'enable-crash-reporter-for-testing']
}
},
onPrepare: function() {
const SpecReporter = require('jasmine-spec-reporter');
// add jasmine spec reporter
jasmine.getEnv().addReporter(new SpecReporter({ displayStacktrace: true }));
browser.ignoreSynchronization = false;
},
useAllAngular2AppRoots: true
};
https://riptutorial.com/ 30
if (process.env.TRAVIS) {
config.capabilities = {
browserName: 'firefox'
};
}
exports.config = config;
beforeEach(() => {
browser.get('http://google.com');
});
run in cmd
protractor conf.js
https://riptutorial.com/ 31
Chapter 5: Angular - ForLoop
Syntax
1. < div *ngFor="let item of items; let i = index">{{i}} {{item}}</ div>
Remarks
The *ngFor structural directive runs as a loop in a collection and repeats a piece of html for each
element of a collection.
@View decorator is now deprecated. Developers should be using template or 'templateUrl' properties
for @Component decorator.
Examples
Angular 2 for-loop
<!doctype html>
<html>
<head>
<title>ng for loop in angular 2 with ES5.</title>
<script type="text/javascript" src="https://code.angularjs.org/2.0.0-
alpha.28/angular2.sfx.dev.js"></script>
<script>
var ngForLoop = function () {
this.msg = "ng for loop in angular 2 with ES5.";
this.users = ["Anil Singh", "Sunil Singh", "Sushil Singh", "Aradhya", 'Reena'];
};
ngForLoop.annotations = [
new angular.Component({
selector: 'ngforloop'
}),
new angular.View({
template: '<H1>{{msg}}</H1>' +
'<p> User List : </p>' +
'<ul>' +
'<li *ng-for="let user of users">' +
'{{user}}' +
'</li>' +
'</ul>',
directives: [angular.NgFor]
})
];
document.addEventListener("DOMContentLoaded", function () {
angular.bootstrap(ngForLoop);
});
</script>
https://riptutorial.com/ 32
</head>
<body>
<ngforloop></ngforloop>
<h2>
<a href="http://www.code-sample.com/" target="_blank">For more detail...</a>
</h2>
</body>
</html>
The NgFor directive instantiates a template once per item from an iterable. The context for each
instantiated template inherits from the outer context with the given loop variable set to the current
item from the iterable.
To customize the default tracking algorithm, NgFor supports trackBy option. trackBy takes a
function which has two arguments: index and item. If trackBy is given, Angular tracks changes by
the return value of the function.
Additional Options: NgFor provides several exported values that can be aliased to local
variables:
• index will be set to the current loop iteration for each template context.
• first will be set to a boolean value indicating whether the item is the first one in the iteration.
• last will be set to a boolean value indicating whether the item is the last one in the iteration.
• even will be set to a boolean value indicating whether this item has an even index.
• odd will be set to a boolean value indicating whether this item has an odd index.
<table>
<thead>
<th>Name</th>
<th>Index</th>
</thead>
<tbody>
<tr *ngFor="let hero of heroes">
<td>{{hero.name}}</td>
</tr>
</tbody>
</table>
@Component({
selector: 'main-component',
template: '<example-component
https://riptutorial.com/ 33
*ngFor="let hero of heroes"
[hero]="hero"></example-component>'
})
@Component({
selector: 'example-component',
template: '<div>{{hero?.name}}</div>'
})
https://riptutorial.com/ 34
Chapter 6: Angular 2 Change detection and
manual triggering
Examples
Basic example
Parent component :
@Component({
selector: 'parent-component',
templateUrl: './parent-component.html'
})
export class ParentComponent {
users : Array<User> = [];
changeUsersActivation(user : User){
user.changeButtonState();
}
constructor(){
this.users.push(new User('Narco', false));
this.users.push(new User('Bombasto',false));
this.users.push(new User('Celeritas', false));
this.users.push(new User('Magneta', false));
}
}
changeButtonState(){
this.active = !this.active;
}
constructor(_firstName :string, _active : boolean){
this.firstName = _firstName;
this.active = _active;
}
Parent HTML:
<div>
<child-component [usersDetails]="users"
(changeUsersActivation)="changeUsersActivation($event)">
</child-component>
</div>
child component :
https://riptutorial.com/ 35
import {Component, Input, EventEmitter, Output} from '@angular/core';
import {User} from "./parent.component";
@Component({
selector: 'child-component',
templateUrl: './child-component.html',
styles: [`
.btn {
height: 30px;
width: 100px;
border: 1px solid rgba(0, 0, 0, 0.33);
border-radius: 3px;
margin-bottom: 5px;
}
`]
})
export class ChildComponent{
@Input() usersDetails : Array<User> = null;
@Output() changeUsersActivation = new EventEmitter();
triggerEvent(user : User){
this.changeUsersActivation.emit(user);
}
}
child HTML :
<div>
<div>
<table>
<thead>
<tr>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody *ngIf="user !== null">
<tr *ngFor="let user of usersDetails">
<td>{{user.firstName}}</td>
<td><button class="btn" (click)="triggerEvent(user)">{{user.active}}</button></td>
</tr>
</tbody>
</table>
</div>
</div>
https://riptutorial.com/ 36
Chapter 7: Angular 2 Data Driven Forms
Remarks
this.myForm = this.formBuilder.group
creates a form object with user's configuration and assigns it to this.myForm variable.
'loginCredentials': this.formBuilder.group
method creates a group of controls which consist of a formControlName eg. login and value ['',
Validators.required], where the first parameter is the initial value of the form input and the secons
is a validator or an array of validators as in 'email': ['', [Validators.required, customValidator]],
.
'hobbies': this.formBuilder.array
Creates an array of groups where the index of the group is formGroupName in the array and is
accessed like :
onAddHobby() {
(<FormArray>this.myForm.find('hobbies')).push(new FormGroup({
'hobby': new FormControl('', Validators.required)
}))
}
this sample method adds new formGroup to the array. Currently accessing requires specifing the
type of control we want to access, in this example this type is : <FormArray>
removeHobby(index: number){
(<FormArray>this.myForm.find('hobbies')).removeAt(index);
}
same rules as above apply to removing a specific form control from the array
Examples
Data driven form
Component
https://riptutorial.com/ 37
import {Component, OnInit} from '@angular/core';
import {
FormGroup,
FormControl,
FORM_DIRECTIVES,
REACTIVE_FORM_DIRECTIVES,
Validators,
FormBuilder,
FormArray
} from "@angular/forms";
import {Control} from "@angular/common";
@Component({
moduleId: module.id,
selector: 'app-data-driven-form',
templateUrl: 'data-driven-form.component.html',
styleUrls: ['data-driven-form.component.css'],
directives: [FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES]
})
export class DataDrivenFormComponent implements OnInit {
myForm: FormGroup;
ngOnInit() {
this.myForm = this.formBuilder.group({
'loginCredentials': this.formBuilder.group({
'login': ['', Validators.required],
'email': ['', [Validators.required, customValidator]],
'password': ['', Validators.required]
}),
'hobbies': this.formBuilder.array([
this.formBuilder.group({
'hobby': ['', Validators.required]
})
])
});
}
removeHobby(index: number){
(<FormArray>this.myForm.find('hobbies')).removeAt(index);
}
onAddHobby() {
(<FormArray>this.myForm.find('hobbies')).push(new FormGroup({
'hobby': new FormControl('', Validators.required)
}))
}
onSubmit() {
console.log(this.myForm.value);
}
}
https://riptutorial.com/ 38
HTML Markup
<h3>Register page</h3>
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<div formGroupName="loginCredentials">
<div class="form-group">
<div>
<label for="login">Login</label>
<input id="login" type="text" class="form-control" formControlName="login">
</div>
<div>
<label for="email">Email</label>
<input id="email" type="text" class="form-control" formControlName="email">
</div>
<div>
<label for="password">Password</label>
<input id="password" type="text" class="form-control" formControlName="password">
</div>
</div>
</div>
<div class="row" >
<div formGroupName="hobbies">
<div class="form-group">
<label>Hobbies array:</label>
<div *ngFor="let hobby of myForm.find('hobbies').controls; let i = index">
<div formGroupName="{{i}}">
<input id="hobby_{{i}}" type="text" class="form-control" formControlName="hobby">
<button *ngIf="myForm.find('hobbies').length > 1"
(click)="removeHobby(i)">x</button>
</div>
</div>
<button (click)="onAddHobby()">Add hobby</button>
</div>
</div>
</div>
<button type="submit" [disabled]="!myForm.valid">Submit</button>
</form>
https://riptutorial.com/ 39
Chapter 8: Angular 2 Forms Update
Remarks
Angular 2 allow to access the ngForm instance by creating a local template variable. Angular 2
exposes directive instances like ngForm by specifying exportAs property of the directive metadata.
Now, the advantage here is without much coding you can access the ngForm instance and use it
to access submitted values or to check if all the fields are valid using properties (valid, submitted,
value etc).
ngForm emits the event "ngSubmit" when it's submitted (Check @Output documentation for more
details of event emitter)
(ngSubmit)= "login(f.value,f.submitted)"
When form is submitted, f.value has the JSON object representing the submitted values.
Examples
Simple Password Change Form with Multi Control Validation
The below examples use the new form API introduced in RC3.
pw-change.template.html
https://riptutorial.com/ 40
</div>
<button type="submit">Submit</button>
</form>
pw-change.component.ts
@Component({
moduleId: module.id
selector: 'pw-change-form',
templateUrl: `./pw-change.template.html`,
directives: [REACTIVE_FORM_DIRECTIVES]
})
// Properties that store paths to FormControls makes our template less verbose
current: AbstractControl;
newPW: AbstractControl;
confirm: AbstractControl;
pw-validators.ts
https://riptutorial.com/ 41
}
@Component({
selector: 'login',
template: `
<h2>Login</h2>
<form #f="ngForm" (ngSubmit)="login(f.value,f.valid)" novalidate>
<div>
<label>Username</label>
<input type="text" [(ngModel)]="username" placeholder="enter username" required>
</div>
<div>
<label>Password</label>
<input type="password" name="password" [(ngModel)]="password" placeholder="enter
password" required>
</div>
<input class="btn-primary" type="submit" value="Login">
</form>`
//For long form we can use **templateUrl** instead of template
})
if(valid){
console.log(valid);
}
}
}
https://riptutorial.com/ 42
Angular 2 Form - Custom Email/Password Validation
App index ts
bootstrap(MyForm);
Custom validator
Form Components ts
@Component({
selector: 'my-form',
templateUrl: 'app/my-form.component.html',
directives: [FORM_DIRECTIVES],
styleUrls: ['styles.css']
})
export class MyForm {
email: Control;
password: Control;
group: ControlGroup;
constructor(builder: FormBuilder) {
this.email = new Control('',
Validators.compose([Validators.required, CustomValidators.emailFormat])
);
this.group = builder.group({
email: this.email,
password: this.password
});
}
onSubmit() {
console.log(this.group.value);
https://riptutorial.com/ 43
}
}
<div>
<label for="email">Email:</label>
<input type="email" id="email" [ngFormControl]="email">
<div>
<label for="password">Password:</label>
<input type="password" id="password" [ngFormControl]="password">
<button type="submit">Register</button>
</form>
registration-form.component.ts
import { FormGroup,
FormControl,
FormBuilder,
Validators } from '@angular/forms';
@Component({
templateUrl: "./registration-form.html"
})
export class ExampleComponent {
constructor(private _fb: FormBuilder) { }
exampleForm = this._fb.group({
name: ['DefaultValue', [<any>Validators.required, <any>Validators.minLength(2)]],
email: ['[email protected]', [<any>Validators.required, <any>Validators.minLength(2)]]
})
registration-form.html
https://riptutorial.com/ 44
<form [formGroup]="exampleForm" novalidate (ngSubmit)="submit(exampleForm)">
<label>Name: </label>
<input type="text" formControlName="name"/>
<label>Email: </label>
<input type="email" formControlName="email"/>
<button type="submit">Submit</button>
</form>
app.module.ts
Add these into your app.module.ts file to use reactive forms
app.component.ts
this.addForm = this.formBuilder.group({
username: ['', Validators.required],
email: ['', Validators.required],
role: ['', Validators.required],
https://riptutorial.com/ 45
password: ['', Validators.required],
password2: ['', Validators.required] },
{ validator: matchingPasswords('password', 'password2')
})
};
addUser() {
if (this.addForm.valid) {
var adduser = {
username: this.addForm.controls['username'].value,
email: this.addForm.controls['email'].value,
password: this.addForm.controls['password'].value,
profile: {
role: this.addForm.controls['role'].value,
name: this.addForm.controls['username'].value,
email: this.addForm.controls['email'].value
}
};
console.log(adduser);// adduser var contains all our form values. store it where you
want
this.addForm.reset();// this will reset our form values to null
}
}
}
app.component.html
<div>
<form [formGroup]="addForm">
<input type="text" placeholder="Enter username" formControlName="username" />
<input type="text" placeholder="Enter Email Address" formControlName="email"/>
<input type="password" placeholder="Enter Password" formControlName="password" />
<input type="password" placeholder="Confirm Password" name="password2"
formControlName="password2"/>
<div class='error' *ngIf="addForm.controls.password2.touched">
<div class="alert-danger errormessageadduser"
*ngIf="addForm.hasError('mismatchedPasswords')"> Passwords do
not match
</div>
</div>
<select name="Role" formControlName="role">
<option value="admin" >Admin</option>
<option value="Accounts">Accounts</option>
<option value="guest">Guest</option>
</select>
<br/>
<br/>
<button type="submit" (click)="addUser()"><span><i class="fa fa-user-plus" aria-
hidden="true"></i></span> Add User </button>
</form>
</div>
validators.ts
https://riptutorial.com/ 46
[key: string]: any
} => {
let password = group.controls[passwordKey];
let confirmPassword = group.controls[confirmPasswordKey];
FormComponent.ts
@Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.scss'],
providers : [FormBuilder]
})
constructor(fb: FormBuilder) {
this.form = fb.group({
FirstName : new FormControl({value: null}, Validators.compose([Validators.required,
Validators.maxLength(15)])),
LastName : new FormControl({value: null}, Validators.compose([Validators.required,
Validators.maxLength(15)])),
Email : new FormControl({value: null}, Validators.compose([
Validators.required,
Validators.maxLength(15),
Validators.pattern(this.emailRegex)]))
});
}
}
form.component.html
https://riptutorial.com/ 47
<div class="row input-label">
<label class="form-label" for="LastName">Last name</label>
<input
[formControl]="form.controls['LastName']"
type="text"
class="form-control"
id="LastName"
name="LastName">
</div>
<div class="row">
<label class="form-label" for="Email">Email</label>
<input
[formControl]="form.controls['Email']"
type="email"
class="form-control"
id="Email"
name="Email">
</div>
<div class="row">
<button
(click)="submit()"
role="button"
class="btn btn-primary submit-btn"
type="button"
[disabled]="!form.valid">Submit</button>
</div>
</div>
</form>
https://riptutorial.com/ 48
Chapter 9: Angular material design
Examples
Md2Select
Component:
<md2-select></md2-select>
<md2-option></md2-option>
<md2-select-header></md2-select-header>
Md2Tooltip
Tooltip is a directive, it allows the user to show hint text while the user mouse hover over an
element.
Md2Toast
@Component({
selector: "..."
})
...
constructor(private toast: Md2Toast) { }
toastMe() {
https://riptutorial.com/ 49
this.toast.show('Toast message...');
--- or ---
...
Md2Datepicker
<md2-datepicker [(ngModel)]="date"></md2-datepicker>
Md2Collapse : Collapse is a directive, it's allow the user to toggle visiblity of the section.
Examples
<div [collapse]="isCollapsed">
Lorum Ipsum Content
</div>
Md2Accordion : Accordion it's allow the user to toggle visiblity of the multiple sections.
Examples
<md2-accordion [multiple]="multiple">
<md2-accordion-tab *ngFor="let tab of accordions"
[header]="tab.title"
[active]="tab.active"
[disabled]="tab.disabled">
{{tab.content}}
</md2-accordion-tab>
<md2-accordion-tab>
<md2-accordion-header>Custom Header</md2-accordion-header>
test content
</md2-accordion-tab>
</md2-accordion>
https://riptutorial.com/ 50
Chapter 10: angular redux
Examples
Basic
app.module.ts
app.store.ts
app.reducer.ts
store.ts
https://riptutorial.com/ 51
export interface IAppState {
example?: string;
}
actions.ts
@Injectable()
export class exampleService {
constructor(@Inject(AppStore) private store: Redux.Store<AppState>) {}
getExampleState(){
console.log(this.store.getState().example);
}
}
change state
@Injectable()
export class exampleService {
constructor(@Inject(AppStore) private store: Redux.Store<AppState>) {}
setExampleState(){
this.store.dispatch(updateExample("new value"));
}
}
actions.ts
https://riptutorial.com/ 52
example?: string;
}
app.store.ts
https://riptutorial.com/ 53
Chapter 11: Angular RXJS Subjects and
Observables with API requests
Remarks
Making API requests with Angular 2 Http service and RxJS is very similar to working with promises
in Angular 1.x.
Use the Http class to make requests. The Http class exposes the methods for issuing HTTP
requests GET, POST, PUT, DELETE, PATCH, HEAD requests via corresponding methods. It also exposes a
generic request method for issuing any kind of HTTP request.
All methods of the Http class return an Observable<Response>, to which you can apply RxJS
operations. You call the .subscribe() method and pass in a function to be called when data is
returned in the Observable stream.
The Observable stream for a request contains only one value - the Response, and completes/settles
when the HTTP request is completed succesfully, or errors/faults if an error is thrown.
Note, the observables returned by the Http module are cold, which means if you subscribe to the
observable multiple times, the originating request will be executed once for each subscription. This
can happen if you want to consume the result in multiple components of your application. For GET
requests this might just cause some extra requests, but this can create unexpected results if
subscribe more than once to PUT or POST requests.
Examples
Basic request
The following example demonstrates a simple HTTP GET request. http.get() returns an
Observable which has the method subscribe. This one appends the returned data to the posts array.
var posts = []
getPosts(http: Http):void {
this.http.get(`https://jsonplaceholder.typicode.com/posts`)
.map(response => response.json())
.subscribe(post => posts.push(post));
}
It may be a good idea to encapsulate the HTTP handling logic in its own class. The following class
exposes a method for getting Posts. It calls the http.get() method and calls .map on the returned
Observable to convert the Response object to a Post object.
https://riptutorial.com/ 54
import {Injectable} from "@angular/core";
import {Http, Response} from "@angular/http";
@Injectable()
export class BlogApi {
The previous example uses a Post class to hold the returned data, which could look as follows:
constructor(src: any) {
this.userId = src && src.userId;
this.id = src && src.id;
this.title = src && src.title;
this.body = src && src.body;
}
}
A component now can use the BlogApi class to easily retrieve Post data without concerning itself
with the workings of the Http class.
One common scenario is to wait for a number of requests to finish before continuing. This can be
accomplished using the forkJoin method.
In the following example, forkJoin is used to call two methods that return Observables. The callback
specified in the .subscribe method will be called when both Observables complete. The
parameters supplied by .subscribe match the order given in the call to .forkJoin. In this case, first
posts then tags.
loadData() : void {
Observable.forkJoin(
this.blogApi.getPosts(),
this.blogApi.getTags()
).subscribe((([posts, tags]: [Post[], Tag[]]) => {
this.posts = posts;
this.tags = tags;
}));
https://riptutorial.com/ 55
}
Read Angular RXJS Subjects and Observables with API requests online:
https://riptutorial.com/angular2/topic/3577/angular-rxjs-subjects-and-observables-with-api-requests
https://riptutorial.com/ 56
Chapter 12: Angular2 Animations
Introduction
Angular's animation system lets you build animations that run with the same kind of native
performance found in pure CSS animations. You can also tightly integrate your animation logic
with the rest of your application code, for ease of control.
Examples
Basic Animation - Transitions an element between two states driven by a
model attribute.
app.component.html
<div>
<div>
<div *ngFor="let user of users">
<button
class="btn"
[@buttonState]="user.active"
(click)="user.changeButtonState()">{{user.firstName}}</button>
</div>
</div>
</div>
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styles: [`
.btn {
height: 30px;
width: 100px;
border: 1px solid rgba(0, 0, 0, 0.33);
border-radius: 3px;
margin-bottom: 5px;
}
`],
animations: [
trigger('buttonState', [
state('true', style({
background: '#04b104',
transform: 'scale(1)'
})),
state('false', style({
https://riptutorial.com/ 57
background: '#e40202',
transform: 'scale(1.1)'
})),
transition('true => false', animate('100ms ease-in')),
transition('false => true', animate('100ms ease-out'))
])
]
})
export class AppComponent {
users : Array<User> = [];
constructor(){
this.users.push(new User('Narco', false));
this.users.push(new User('Bombasto',false));
this.users.push(new User('Celeritas', false));
this.users.push(new User('Magneta', false));
}
}
changeButtonState(){
this.active = !this.active;
}
constructor(_firstName :string, _active : boolean){
this.firstName = _firstName;
this.active = _active;
}
https://riptutorial.com/ 58
Chapter 13: Angular2 CanActivate
Examples
Angular2 CanActivate
Implemented in a router:
@Injectable()
export class CanActivateRoute implements CanActivate{
constructor(){}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return true;
}
}
https://riptutorial.com/ 59
Chapter 14: Angular2 Custom Validations
Parameters
parameter description
This is the control that is being validated. Typically you will want to see if
control
control.value meets some criteria.
Examples
Custom validator examples:
Angular 2 has two kinds of custom validators. Synchronous validators as in the first example that
will run directly on the client and asynchronous validators (the second example) that you can use
to call a remote service to do the validation for you. In this example the validator should call the
server to see if a value is unique.
return null;
}
If your control value is valid you simply return null to the caller. Otherwise you can return an object
which describes the error.
constructor(fb: FormBuilder) {
this.form = fb.group({
firstInput: ['', Validators.compose([Validators.required,
CustomValidators.cannotContainSpace]), CustomValidators.shouldBeUnique],
secondInput: ['', Validators.required]
https://riptutorial.com/ 60
});
}
Here we use the FormBuilder to create a very basic form with two input boxes. The FromBuilder
takes an array for three arguments for each input control.
1. On initialize:
exampleForm : FormGroup;
constructor(fb: FormBuilder){
this.exampleForm = fb.group({
name : new FormControl({value: 'default name'}, Validators.compose([Validators.required,
Validators.maxLength(15)]))
});
}
2.After initialize:
this.exampleForm.controls['name'].setValue('default name');
https://riptutorial.com/ 61
Chapter 15: Angular2 Databinding
Examples
@Input()
@Component({
selector: 'parent-component',
template: '<div>
<child-component [users]="users"></child-component>
</div>'
})
export class ParentComponent implements OnInit{
let users : List<User> = null;
ngOnInit() {
users.push(new User('A', 'A', '[email protected]');
users.push(new User('B', 'B', '[email protected]');
users.push(new User('C', 'C', '[email protected]');
}
}
@Component({
selector: 'child-component',
template: '<div>
<table *ngIf="users !== null">
<thead>
<th>Name</th>
<th>FName</th>
<th>Email</th>
</thead>
<tbody>
<tr *ngFor="let user of users">
<td>{{user.name}}</td>
<td>{{user.fname}}</td>
<td>{{user.email}}</td>
</tr>
</tbody>
</table>
</div>',
})
export class ChildComponent {
@Input() users : List<User> = null;
}
https://riptutorial.com/ 62
fname : string;
email : string;
https://riptutorial.com/ 63
Chapter 16: Angular2 In Memory Web API
Remarks
I mainly requested this topic because I could not find any information on setting up multiple API
routes with the Angular2-In-Memory-Web-Api. Ended up figuring it out myself, and figured this
might be helpful to others.
Examples
Basic Setup
mock-data.ts
return {mock};
}
}
main.ts
Have the dependency injector provide the InMemoryBackendService for XHRBackend requests.
Also, provide a class that includes a
createDb()
function (in this case, MockData) specifying the mocked API routes for SEED_DATA requests.
bootstrap(AppComponent, [
HTTP_PROVIDERS,
{ provide: XHRBackend, useClass: InMemoryBackendService },
{ provide: SEED_DATA, useClass: MockData }
]);
https://riptutorial.com/ 64
mock.service.ts
@Injectable()
export class MockService {
// URL to web api
private mockUrl = 'app/mock';
getData(): Promise<Mock[]> {
return this.http.get(this.mockUrl)
.toPromise()
.then(this.extractData)
.catch(this.handleError);
}
mock-data.ts
let data = [
{ id: '1', name: 'Data A' },
{ id: '2', name: 'Data B' },
{ id: '3', name: 'Data C' }
];
https://riptutorial.com/ 65
app/mock
and
app/data
https://riptutorial.com/ 66
Chapter 17: Angular2 Input() output()
Examples
Input()
@Component({
selector: 'parent-component',
template: '<div>
<child-component [users]="users"></child-component>
</div>'
})
export class ParentComponent implements OnInit{
let users : List<User> = null;
ngOnInit() {
users.push(new User('A', 'A', '[email protected]');
users.push(new User('B', 'B', '[email protected]');
users.push(new User('C', 'C', '[email protected]');
}
}
@Component({
selector: 'child-component',
template: '<div>
<table *ngIf="users !== null">
<thead>
<th>Name</th>
<th>FName</th>
<th>Email</th>
</thead>
<tbody>
<tr *ngFor="let user of users">
<td>{{user.name}}</td>
<td>{{user.fname}}</td>
<td>{{user.email}}</td>
</tr>
</tbody>
</table>
</div>',
})
export class ChildComponent {
@Input() users : List<User> = null;
}
https://riptutorial.com/ 67
fname : string;
email : string;
<child-component [isSelected]="inputPropValue"></child-component>
Parent element ts
<div [class.simpleCssClass]="inputPropValue"></div>
This code will send the inputPropValue from the parent component to the child and it will have the
value we have set in the parent component when it arrives there - false in our case. We can then
use that value in the child component to, for example add a class to an element.
https://riptutorial.com/ 68
Chapter 18: Angular2 provide external data to
App before bootstrap
Introduction
In this post I will demonstrate how to pass external data to Angular app before the app bootstraps.
This external data could be configuration data, legacy data, server rendered etc.
Examples
Via Dependency Injection
Instead of invoking the Angular’s bootstrap code directly, wrap the bootstrap code into a function
and export the function. This function can also accept parameters.
Then, in any services or components we can inject the “legacy model” and gain access to it.
require(["myAngular2App"], function(app) {
app.runAngular2App(legacyModel); // Input to your APP
});
https://riptutorial.com/ 69
Chapter 19: Angular2 using webpack
Examples
Angular 2 webpack setup
webpack.config.js
module.exports = {
"resolve": {
"extensions": ['.ts', '.js'],
},
"module": {
"rules": [
{
"test": /\.ts$/,
"loaders": [
{
"loader": 'awesome-typescript-loader',
"options": {
"configFileName": helpers.root("./tsconfig.json")
}
},
"angular2-template-loader"
]
},
],
},
"plugins": [
https://riptutorial.com/ 70
"manifest": helpers.root("config/polyfills-manifest.json")
}),
// minify compiled js
new webpack.optimize.UglifyJsPlugin(),
],
}
vendor.config.js
module.exports = {
// specify vendor file where all vendors are imported
"entry": {
// optionally add your shims as well
"polyfills": [helpers.root("src/app/shims.ts")],
"vendor": [helpers.root("src/app/vendor.ts")],
},
"resolve": {
"extensions": ['.ts', '.js'],
},
"module": {
"rules": [
{
"test": /\.ts$/,
"loaders": [
{
"loader": 'awesome-typescript-loader',
"options": {
"configFileName": helpers.root("./tsconfig.json")
}
},
]
},
],
},
"plugins": [
https://riptutorial.com/ 71
"name": "[name]",
"context": helpers.root("src/app"),
"path": helpers.root("config/[name]-manifest.json")
}),
// minify generated js
new webpack.optimize.UglifyJsPlugin(),
],
}
helpers.js
function root(args) {
args = Array.prototype.slice.call(arguments, 0);
return path.join.apply(path, [_root].concat(args));
}
exports.root = root;
vendor.ts
import "@angular/platform-browser"
import "@angular/platform-browser-dynamic"
import "@angular/core"
import "@angular/common"
import "@angular/http"
import "@angular/router"
import "@angular/forms"
import "rxjs"
index.html
<!DOCTYPE html>
<html>
<head>
<title>Angular 2 webpack</title>
package.json
{
"name": "webpack example",
"version": "0.0.0",
"description": "webpack",
"scripts": {
https://riptutorial.com/ 72
"build:webpack": "webpack --config config/webpack.config.js",
"build:vendor": "webpack --config config/vendor.config.js",
"watch": "webpack --config config/webpack.config.js --watch"
},
"devDependencies": {
"@angular/common": "2.4.7",
"@angular/compiler": "2.4.7",
"@angular/core": "2.4.7",
"@angular/forms": "2.4.7",
"@angular/http": "2.4.7",
"@angular/platform-browser": "2.4.7",
"@angular/platform-browser-dynamic": "2.4.7",
"@angular/router": "3.4.7",
"webpack": "^2.2.1",
"awesome-typescript-loader": "^3.1.2",
},
"dependencies": {
}
}
https://riptutorial.com/ 73
Chapter 20: Angular-cli
Introduction
Here you will find how to start with angular-cli , generating new component/service/pipe/module
with angular-cli , add 3 party like bootstrap , build angular project.
Examples
Create empty Angular2 application with angular-cli
Requirements:
Run the following commands with cmd from new directory folder:
just use your cmd: You can use the ng generate (or just ng g) command to generate Angular
components:
https://riptutorial.com/ 74
1. npm install ng2-bootstrap --save or yarn add ng2-bootstrap
"scripts": [
"../node_modules/jquery/dist/jquery.js",
"../node_modules/bootstrap/dist/js/bootstrap.js"
]
When building you can modify base tag () in your index.html with --base-href your-url option.
The default style files generated and compiled by @angular/cli are css.
Yarn is an alternative for npm, the default package manager on @angular/cli. If you want to use
yarn as package manager for @angular/cli follow this steps:
https://riptutorial.com/ 75
Requirements
• yarn (npm install --global yarn or see the installation page)
• @angular/cli (npm install -g @angular/cli or yarn global add @angular/cli)
https://riptutorial.com/ 76
Chapter 21: angular-cli test coverage
Introduction
test coverage is defined as a technique which determines whether our test cases are actually
covering the application code and how much code is exercised when we run those test cases.
Angular CLI has built in code coverage feature with just a simple command ng test --cc
Examples
A simple angular-cli command base test coverage
If you want to see overall test coverage statistics than of course in Angular CLI you can just type
below command, and see the bottom of your command prompt window for results.
if you want to see component's individual coverage of tests follow these steps.
note that list of reporters is comma-separated, as we have added a new reporter, teamcity.
after running this command you can see the folder coverage in your dir and open index.html for a
graphical view of test coverage.
https://riptutorial.com/ 77
You can also set the coverage threshold that you want to achieve, in karma.conf.js, like this.
coverageIstanbulReporter: {
reports: ['html', 'lcovonly'],
fixWebpackSourcePaths: true,
thresholds: {
statements: 90,
lines: 90,
branches: 90,
functions: 90
}
},
https://riptutorial.com/ 78
Chapter 22: Animation
Examples
Transition between null states
@Component({
...
animations: [
trigger('appear', [
transition(':enter', [
style({
//style applied at the start of animation
}),
animate('300ms ease-in', style({
//style applied at the end of animation
}))
])
])
]
})
class AnimComponent {
}
]
The <div> in this template grows to 50px and then 100px and then shrinks back to 20px when you
click the button.
The logic for whichever state is active can be managed in the component logic. In this case, the
component variable size holds the string value "small", "medium" or "large".
The <div> element respond to that value through the trigger specified in the @Component metadata:
[@size]="size".
@Component({
template: '<div [@size]="size">Some Text</div><button
(click)="toggleSize()">TOGGLE</button>',
animations: [
trigger('size', [
state('small', style({
height: '20px'
})),
state('medium', style({
height: '50px'
})),
state('large', style({
height: '100px'
https://riptutorial.com/ 79
})),
transition('small => medium', animate('100ms')),
transition('medium => large', animate('200ms')),
transition('large => small', animate('300ms'))
])
]
})
export class TestComponent {
size: string;
constructor(){
this.size = 'small';
}
toggleSize(){
switch(this.size) {
case 'small':
this.size = 'medium';
break;
case 'medium':
this.size = 'large';
break;
case 'large':
this.size = 'small';
}
}
}
https://riptutorial.com/ 80
Chapter 23: Attribute directives to affect the
value of properties on the host node by using
the @HostBinding decorator.
Examples
@HostBinding
The @HostBinding decorator allows us to programatically set a property value on the directive's
host element. It works similarly to a property binding defined in a template, except it specifically
targets the host element. The binding is checked for every change detection cycle, so it can
change dynamically if desired. For example, lets say that we want to create a directive for buttons
that dynamically adds a class when we press on it. That could look something like:
@Directive({
selector: '[appButtonPress]'
})
export class ButtonPressDirective {
@HostBinding('attr.role') role = 'button';
@HostBinding('class.pressed') isPressed: boolean;
@HostListener('mousedown') hasPressed() {
this.isPressed = true;
}
@HostListener('mouseup') hasReleased() {
this.isPressed = false;
}
}
Notice that for both use cases of @HostBinding we are passing in a string value for which property
we want to affect. If we don't supply a string to the decorator, then the name of the class member
will be used instead. In the first @HostBinding, we are statically setting the role attribute to button.
For the second example, the pressed class will be applied when isPressed is true
Read Attribute directives to affect the value of properties on the host node by using the
@HostBinding decorator. online: https://riptutorial.com/angular2/topic/9455/attribute-directives-to-
affect-the-value-of-properties-on-the-host-node-by-using-the--hostbinding-decorator-
https://riptutorial.com/ 81
Chapter 24: Barrel
Introduction
A barrel is a way to rollup exports from several ES2015 modules into a single convenience
ES2015 module. The barrel itself is an ES2015 module file that re-exports selected exports of
other ES2015 modules.
Examples
Using Barrel
For example without a barrel, a consumer would need three import statements:
We can add a barrel by creating a file in the same component folder. In this case the folder is
called 'heroes' named index.ts (using the conventions) that exports all of these items:
Still, this can become a very long line; which could be reduced further.
That's pretty reduced! The * as h imports all of the modules and aliases as h
https://riptutorial.com/ 82
Chapter 25: Bootstrap Empty module in
angular 2
Examples
An empty module
@NgModule({
declarations: [], // components your module owns.
imports: [], // other modules your module needs.
providers: [], // providers available to your module.
bootstrap: [] // bootstrap this root component.
})
export class MyModule {}
// app.module.ts
@NgModule({
declarations: [MyRootComponent],
imports: [BrowserModule, HttpModule],
bootstrap: [MyRootComponent]
})
export class MyModule {}
MyRootComponent is the root component packaged in MyModule. It is the entry point to your Angular 2
application.
platformBrowserDynamic().bootstrapModule( MyModule );
In this example, MyModule is the module containing your root component. By bootstrapping MyModule
your Angular 2 app is ready to go.
https://riptutorial.com/ 83
Application Root Module
@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
We can statically bootstrap an application by taking the plain ES5 Javascript output of the
generated factory classes. Then we can use that output to bootstrap the application:
This will cause the application bundle to be much smaller, because all the template compilation
was already done in a build step, using either ngc or calling its internals directly.
https://riptutorial.com/ 84
Chapter 26: Brute Force Upgrading
Introduction
If you want to upgrade the Angular CLI version of your project you may run into tough-to-fix errors
and bugs from simply changing the Angular CLI version number in your project. Also, because the
Angular CLI hides a lot of what's going on in the build and bundles process, you can't really do
much when things go wrong there.
Sometimes the easiest way to update the Angular CLI version of the project is to just scaffold out a
new proejct with the Angular CLI version that you wish to use.
Remarks
Because Angular 2 is so modular and encapsulated you can pretty much just copy over all of your
components, services, pipes, directives and then fill out the NgModule as it was in the old project.
Examples
Scaffolding a New Angular CLI Project
ng new NewProject
or
ng init NewProject
https://riptutorial.com/ 85
Chapter 27: Bypassing Sanitizing for trusted
values
Parameters
Params Details
Remarks
SUPER IMPORTANT!
DISABLING SANITIZING LEAVES YOU AT RISK OF XSS
(Cross-Site Scripting) AND OTHER ATTACK VECTORS.
PLEASE MAKE SURE YOU TRUST WHAT YOU'RE GETTING
100%
Using Pipes relegates you to only changing attribute values like so :
or this way
Examples
Bypassing Sanitizing with pipes (for code re-use)
https://riptutorial.com/ 86
Project is following the structure from the Angular2 Quickstart guide here.
RootOfProject
|
+-- app
| |-- app.component.ts
| |-- main.ts
| |-- pipeUser.component.ts
| \-- sanitize.pipe.ts
|
|-- index.html
|-- main.html
|-- pipe.html
main.ts
bootstrap(AppComponent);
This finds the index.html file in the root of the project, and builds off of that.
app.component.ts
@Component({
selector: 'main-app',
templateUrl: 'main.html',
directives: [PipeUserComponent]
})
This is the top level component that groups other components that are used.
pipeUser.component.ts
@Component({
selector: 'pipe-example',
templateUrl: "pipe.html",
pipes: [IgnoreSanitize]
})
https://riptutorial.com/ 87
return this.unsafeValue.concat(input);
// returns : "unsafe/picUrl?id=input"
} else {
return "fallback/to/something";
}
}
}
This component provides the view for the Pipe to work with.
sanitize.pipe.ts
@Pipe({
name: 'sanitaryPipe'
})
export class IgnoreSanitize implements PipeTransform {
index.html
<head>
Stuff goes here...
</head>
<body>
<main-app>
main.html will load inside here.
</main-app>
</body>
main.html
<othertags>
</othertags>
<pipe-example>
pipe.html will load inside here.
</pipe-example>
<moretags>
</moretags>
pipe.html
https://riptutorial.com/ 88
<img [src]="getUrl('1234') | sanitaryPipe">
<embed [src]="getUrl() | sanitaryPipe">
If you were to inspect the html while the app is running you would see that it looks like this:
<head>
Stuff goes here...
</head>
<body>
<othertags>
</othertags>
<moretags>
</moretags>
</body>
https://riptutorial.com/ 89
Chapter 28: Commonly built-in directives and
services
Introduction
@angular/common - commonly needed directives and services @angular/core - the angular core
framework
Examples
Location Class
Location is a service that applications can use to interact with a browser's URL. Depending on
which LocationStrategy is used, Location will either persist to the URL's path or the URL's hash
segment.
Location is responsible for normalizing the URL against the application's base href.
@Component({
selector: 'app-component'
})
class AppCmp {
constructor(_location: Location) {
//Changes the browsers URL to the normalized version of the given URL,
//and pushes a new item onto the platform's history.
_location.go('/foo');
backClicked() {
//Navigates back in the platform's history.
this._location.back();
}
forwardClicked() {
//Navigates forward in the platform's history.
this._location.back();
}
}
AsyncPipe
The async pipe subscribes to an Observable or Promise and returns the latest value it has
emitted. When a new value is emitted, the async pipe marks the component to be checked for
https://riptutorial.com/ 90
changes. When the component gets destroyed, the async pipe unsubscribes automatically to
avoid potential memory leaks.
@Component({
selector: 'async-observable-pipe',
template: '<div><code>observable|async</code>: Time: {{ time | async }}</div>'
})
export class AsyncObservablePipeComponent {
time = new Observable<string>((observer: Subscriber<string>) => {
setInterval(() => observer.next(new Date().toString()), 1000);
});
}
@Component({
selector: 'my-app',
template: `<h1>Hello {{name}}</h1>
<h2>Current Version: {{ver}}</h2>
`,
})
export class AppComponent {
name = 'Angular2';
ver = VERSION.full;
}
Currency Pipe
The currency pipe allows you to work with you data as regular numbers but display it with standard
currency formatting (currency symbol, decimal places, etc.) in the view.
@Component({
selector: 'currency-pipe',
template: `<div>
<p>A: {{myMoney | currency:'USD':false}}</p>
<p>B: {{yourMoney | currency:'USD':true:'4.2-2'}}</p>
</div>`
})
export class CurrencyPipeComponent {
myMoney: number = 100000.653;
yourMoney: number = 5.3495;
}
https://riptutorial.com/ 91
https://angular.io/docs/ts/latest/api/common/index/CurrencyPipe-pipe.html
https://riptutorial.com/ 92
Chapter 29: Component interactions
Syntax
• <element [variableName]="value"></element> //Declaring input to child when using @Input()
method.
• <element (childOutput)="parentFunction($event)"></element> //Declaring output from child
when using @Output() method.
• @Output() pageNumberClicked = new EventEmitter(); //Used for sending output data from child
component when using @Output() method.
• this.pageNumberClicked.emit(pageNum); //Used to trigger data output from child component.
when using @Output() method.
• @ViewChild(ComponentClass) //Property decorator is required when using ViewChild.
Parameters
Name Value
Examples
Parent - Child interaction using @Input & @Output properties
We have a DataListComponent that shows a data we pull from a service. DataListComponent also
has a PagerComponent as it's child.
PagerComponent creates page number list based on total number of pages it gets from the
DataListComponent. PagerComponent also lets the DataListComponent know when user clicks
any page number via Output property.
@Component({
selector: 'datalist',
template: `
<table>
<tr *ngFor="let person of personsData">
<td>{{person.name}}</td>
<td>{{person.surname}}</td>
</tr>
</table>
https://riptutorial.com/ 93
<pager [pageCount]="pageCount" (pageNumberClicked)="pageChanged($event)"></pager>
`
})
export class DataListComponent {
private personsData = null;
private pageCount: number;
pageChanged(pageNumber: number){
var response = this.dataListService.getData(pageNumber); //Request data from the
service with new page number
this.personsData = response.persons;
}
}
@NgModule({
imports: [CommonModule],
exports: [],
declarations: [DataListComponent, PagerComponent],
providers: [DataListService],
})
export class DataListModule { }
PagerComponent lists all the page numbers. We set click event on each of them so we can let the
parent know about the clicked page number.
@Component({
selector: 'pager',
template: `
<div id="pager-wrapper">
<span *ngFor="#page of pageCount" (click)="pageClicked(page)">{{page}}</span>
</div>
`
})
export class PagerComponent {
@Input() pageCount: number;
@Output() pageNumberClicked = new EventEmitter();
constructor() { }
pageClicked(pageNum){
this.pageNumberClicked.emit(pageNum); //Send clicked page number as output
}
}
Viewchild offers one way interaction from parent to child. There is no feedback or output from child
when ViewChild is used.
https://riptutorial.com/ 94
We have a DataListComponent that shows some information. DataListComponent has
PagerComponent as it's child. When user makes a search on DataListComponent, it gets a data
from a service and ask PagerComponent to refresh paging layout based on new number of pages.
@Component({
selector: 'datalist',
template: `<input type='text' [(ngModel)]="searchText" />
<button (click)="getData()">Search</button>
<table>
<tr *ngFor="let person of personsData">
<td>{{person.name}}</td>
<td>{{person.surname}}</td>
</tr>
</table>
<pager></pager>
`
})
export class DataListComponent {
private personsData = null;
private searchText: string;
@ViewChild(PagerComponent)
private pagerComponent: PagerComponent;
getData(){
var response = this.dataListService.getData(this.searchText);
this.personsData = response.data;
this.pagerComponent.setPaging(this.personsData / 10); //Show 10 records per page
}
}
@NgModule({
imports: [CommonModule],
exports: [],
declarations: [DataListComponent, PagerComponent],
providers: [DataListService],
})
export class DataListModule { }
Child component is not available until parent component is rendered. Attempting to access to the
child before parents AfterViewInit life cyle hook will cause exception.
https://riptutorial.com/ 95
import { Subject } from 'rxjs/Subject';
@Injectable()
export class ComponentCommunicationService {
componentChanged$ = this.componentChangeSource.asObservable();
dateCreated$ = this.newDateCreationSource.asObservable();
refresh() {
this.componentChangeSource.next();
}
broadcastDate(date: Date) {
this.newDateCreationSource.next(date);
}
}
Parent component:
@Component({
selector: 'parent',
template: `
<button (click)="refreshSubsribed()">Refresh</button>
<h1>Last date from child received: {{lastDate}}</h1>
<child-component></child-component>
`
})
export class ParentComponent implements OnInit {
lastDate: Date;
constructor(private communicationService: ComponentCommunicationService) { }
ngOnInit() {
this.communicationService.dateCreated$.subscribe(newDate => {
this.lastDate = newDate;
});
}
refreshSubsribed() {
this.communicationService.refresh();
}
}
Child component:
@Component({
selector: 'child-component',
template: `
<h1>Last refresh from parent: {{lastRefreshed}}</h1>
<button (click)="sendNewDate()">Send new date</button>
https://riptutorial.com/ 96
`
})
export class ChildComponent implements OnInit {
lastRefreshed: Date;
constructor(private communicationService: ComponentCommunicationService) { }
ngOnInit() {
this.communicationService.componentChanged$.subscribe(event => {
this.onRefresh();
});
}
sendNewDate() {
this.communicationService.broadcastDate(new Date());
}
onRefresh() {
this.lastRefreshed = new Date();
}
}
AppModule:
@NgModule({
declarations: [
ParentComponent,
ChildComponent
],
providers: [ComponentCommunicationService],
bootstrap: [AppComponent] // not included in the example
})
export class AppModule {}
https://riptutorial.com/ 97
Chapter 30: Component interactions
Introduction
Share information between different directives and components.
Examples
Pass data from parent to child with input binding
HeroChildComponent has two input properties, typically adorned with @Input decorations.
Use an input property setter to intercept and act upon a value from the parent.
The setter of the name input property in the child NameChildComponent trims the whitespace from
a name and replaces an empty value with default text.
Here's the NameParentComponent demonstrating name variations including a name with all
spaces:
https://riptutorial.com/ 98
import { Component } from '@angular/core';
@Component({
selector: 'name-parent',
template: `
<h2>Master controls {{names.length}} names</h2>
<name-child *ngFor="let name of names" [name]="name"></name-child>
`
})
export class NameParentComponent {
// Displays 'Mr. IQ', '<no name set>', 'Bombasto'
names = ['Mr. IQ', ' ', ' Bombasto '];
}
The child component exposes an EventEmitter property with which it emits events when
something happens. The parent binds to that event property and reacts to those events.
The child's EventEmitter property is an output property, typically adorned with an @Output
decoration as seen in this VoterComponent:
The parent VoteTakerComponent binds an event handler (onVoted) that responds to the child
event payload ($event) and updates a counter.
https://riptutorial.com/ 99
export class VoteTakerComponent {
agreed = 0;
disagreed = 0;
voters = ['Mr. IQ', 'Ms. Universe', 'Bombasto'];
onVoted(agreed: boolean) {
agreed ? this.agreed++ : this.disagreed++;
}
}
A parent component cannot use data binding to read child properties or invoke child methods. We
can do both by creating a template reference variable for the child element and then reference that
variable within the parent template as seen in the following example.
We have a child CountdownTimerComponent that repeatedly counts down to zero and launches a
rocket. It has start and stop methods that control the clock and it displays a countdown status
message in its own template.
https://riptutorial.com/ 100
<h3>Countdown to Liftoff (via local variable)</h3>
<button (click)="timer.start()">Start</button>
<button (click)="timer.stop()">Stop</button>
<div class="seconds">{{timer.seconds}}</div>
<countdown-timer #timer></countdown-timer>
`,
styleUrls: ['demo.css']
})
export class CountdownLocalVarParentComponent { }
The parent component cannot data bind to the child's start and stop methods nor to its seconds
property.
We can place a local variable (#timer) on the tag () representing the child component. That gives
us a reference to the child component itself and the ability to access any of its properties or
methods from within the parent template.
In this example, we wire parent buttons to the child's start and stop and use interpolation to display
the child's seconds property.
The local variable approach is simple and easy. But it is limited because the parent-child wiring
must be done entirely within the parent template. The parent component itself has no access to
the child.
We can't use the local variable technique if an instance of the parent component class must read
or write child component values or must call child component methods.
When the parent component class requires that kind of access, we inject the child component into
the parent as a ViewChild.
We'll illustrate this technique with the same Countdown Timer example. We won't change its
appearance or behavior. The child CountdownTimerComponent is the same as well.
We are switching from the local variable to the ViewChild technique solely for the purpose of
demonstration. Here is the parent, CountdownViewChildParentComponent:
https://riptutorial.com/ 101
export class CountdownViewChildParentComponent implements AfterViewInit {
@ViewChild(CountdownTimerComponent)
private timerComponent: CountdownTimerComponent;
seconds() { return 0; }
ngAfterViewInit() {
// Redefine `seconds()` to get from the `CountdownTimerComponent.seconds` ...
// but wait a tick first to avoid one-time devMode
// unidirectional-data-flow-violation error
setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);
}
start() { this.timerComponent.start(); }
stop() { this.timerComponent.stop(); }
}
It takes a bit more work to get the child view into the parent component class.
We import references to the ViewChild decorator and the AfterViewInit lifecycle hook.
We inject the child CountdownTimerComponent into the private timerComponent property via the
@ViewChild property decoration.
The #timer local variable is gone from the component metadata. Instead we bind the buttons to the
parent component's own start and stop methods and present the ticking seconds in an
interpolation around the parent component's seconds method.
The ngAfterViewInit lifecycle hook is an important wrinkle. The timer component isn't available
until after Angular displays the parent view. So we display 0 seconds initially.
Then Angular calls the ngAfterViewInit lifecycle hook at which time it is too late to update the
parent view's display of the countdown seconds. Angular's unidirectional data flow rule prevents
us from updating the parent view's in the same cycle. We have to wait one turn before we can
display the seconds.
We use setTimeout to wait one tick and then revise the seconds method so that it takes future
values from the timer component.
A parent component and its children share a service whose interface enables bi-directional
communication within the family.
The scope of the service instance is the parent component and its children. Components outside
this component subtree have no access to the service or their communications.
https://riptutorial.com/ 102
// Observable string sources
private missionAnnouncedSource = new Subject<string>();
private missionConfirmedSource = new Subject<string>();
// Observable string streams
missionAnnounced$ = this.missionAnnouncedSource.asObservable();
missionConfirmed$ = this.missionConfirmedSource.asObservable();
// Service message commands
announceMission(mission: string) {
this.missionAnnouncedSource.next(mission);
}
confirmMission(astronaut: string) {
this.missionConfirmedSource.next(astronaut);
}
}
The MissionControlComponent both provides the instance of the service that it shares with its
children (through the providers metadata array) and injects that instance into itself through its
constructor:
The AstronautComponent also injects the service in its constructor. Each AstronautComponent is
https://riptutorial.com/ 103
a child of the MissionControlComponent and therefore receives its parent's service instance:
Notice that we capture the subscription and unsubscribe when the AstronautComponent is
destroyed. This is a memory-leak guard step. There is no actual risk in this app because the
lifetime of a AstronautComponent is the same as the lifetime of the app itself. That would not
always be true in a more complex application.
We do not add this guard to the MissionControlComponent because, as the parent, it controls the
lifetime of the MissionService. The History log demonstrates that messages travel in both
directions between the parent MissionControlComponent and the AstronautComponent children,
facilitated by the service:
https://riptutorial.com/ 104
Chapter 31: Components
Introduction
Angular components are elements composed by a template that will render your application.
Examples
A simple component
There are other parameters you can configure, but the listed ones are what you will use the most.
A simple example:
@Component({
selector: 'app-required',
styleUrls: ['required.component.scss'],
// template: `This field is required.`,
templateUrl: 'required.component.html',
})
export class RequiredComponent { }
https://riptutorial.com/ 105
Passing a template as an inline code
@Component({
template: `<div>My template here</div>`,
})
Templates may contain styles. The styles declared in @Component are different from your application
style file, anything applied in the component will be restricted to this scope. For example, say you
add:
All divs inside the component will be red, but if you have other components, other divs in your
HTML they will not be changed at all.
@Component({
styleUrls: ['hero.component.css'],
})
You shouldn't use styles with require as it will not work when you build your application to
production.
Testing a Component
hero.component.html
hero.component.ts
https://riptutorial.com/ 106
import { Component } from '@angular/core';
@Component({
selector: 'app-hero',
templateUrl: 'hero.component.html',
})
export class HeroComponent {
public form = new FormGroup({
name: new FormControl('', Validators.required),
});
submit(event) {
console.log(event);
console.log(this.form.controls.name.value);
}
}
hero.component.spec.ts
describe('HeroComponent', () => {
let component: HeroComponent;
let fixture: ComponentFixture<HeroComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [HeroComponent],
imports: [ReactiveFormsModule],
}).compileComponents();
fixture = TestBed.createComponent(HeroComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should log hero name in the console when user submit form', async(() => {
const heroName = 'Saitama';
const element = <HTMLFormElement>fixture.debugElement.nativeElement.querySelector('form');
spyOn(console, 'log').and.callThrough();
component.form.controls['name'].setValue(heroName);
element.querySelector('button').click();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(console.log).toHaveBeenCalledWith(heroName);
});
}));
https://riptutorial.com/ 107
component.form.controls['name'].setValue('');
expect(component.form.invalid).toBeTruthy();
});
});
Nesting components
Components will render in their respective selector, so you can use that to nest components.
@Component({
selector: 'app-required',
template: `{{name}} is required.`
})
export class RequiredComponent {
@Input()
public name: String = '';
}
You can use it inside another component using app-required (this component's selector):
@Component({
selector: 'app-sample',
template: `
<input type="text" name="heroName" />
<app-required name="Hero Name"></app-required>
`
})
export class RequiredComponent {
@Input()
public name: String = '';
}
https://riptutorial.com/ 108
Chapter 32: Configuring ASP.net Core
application to work with Angular 2 and
TypeScript
Introduction
SCENARIO: ASP.NET Core background Angular 2 Front-End Angular 2 Components using
Asp.net Core Controllers
It way can implement Angular 2 over Asp.Net Core app. It let us call MVC Controllers from Angular
2 components too with the MVC result View supporting Angular 2.
Examples
Asp.Net Core + Angular2 + Gulp
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using CoreAngular000.Data;
using CoreAngular000.Models;
using CoreAngular000.Services;
using Microsoft.Extensions.FileProviders;
using System.IO;
namespace CoreAngular000
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange:
true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional:
true);
if (env.IsDevelopment())
{
https://riptutorial.com/ 109
builder.AddUserSecrets<Startup>();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new
PhysicalFileProvider(Path.Combine(env.ContentRootPath, "node_modules")),
RequestPath = "/node_modules"
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
https://riptutorial.com/ 110
}
}
tsConfig.json
{
"compilerOptions": {
"diagnostics": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [ "es2015", "dom" ],
"listFiles": true,
"module": "commonjs",
"moduleResolution": "node",
"noImplicitAny": true,
"outDir": "wwwroot",
"removeComments": false,
"rootDir": "wwwroot",
"sourceMap": true,
"suppressImplicitAnyIndexErrors": true,
"target": "es5"
},
"exclude": [
"node_modules",
"wwwroot/lib/"
]
}
Package.json
{
"name": "angular dependencies and web dev package",
"version": "1.0.0",
"description": "Angular 2 MVC. Samuel Maícas Template",
"scripts": {},
"dependencies": {
"@angular/common": "~2.4.0",
"@angular/compiler": "~2.4.0",
"@angular/core": "~2.4.0",
"@angular/forms": "~2.4.0",
"@angular/http": "~2.4.0",
"@angular/platform-browser": "~2.4.0",
"@angular/platform-browser-dynamic": "~2.4.0",
"@angular/router": "~3.4.0",
"angular-in-memory-web-api": "~0.2.4",
"systemjs": "0.19.40",
"core-js": "^2.4.1",
"rxjs": "5.0.1",
"zone.js": "^0.7.4"
},
"devDependencies": {
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-concat": "^2.6.1",
"gulp-cssmin": "^0.1.7",
"gulp-htmlmin": "^3.0.0",
"gulp-uglify": "^2.1.2",
"merge-stream": "^1.0.1",
"tslint": "^3.15.1",
https://riptutorial.com/ 111
"typescript": "~2.0.10"
},
"repository": {}
}
bundleconfig.json
[
{
"outputFileName": "wwwroot/css/site.min.css",
"inputFiles": [
"wwwroot/css/site.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
"minify": {
"enabled": true,
"renameLocals": true
},
"sourceMap": false
}
]
Views/Home/Index.cshtml
@{
ViewData["Title"] = "Home Page";
}
<div>{{ nombre }}</div>
For wwwroot folder use https://github.com/angular/quickstart seed. You need: index.html main.ts,
systemjs-angular-loader.js, systemjs.config.js, tsconfig.json And the app folder
wwwroot/Index.html
<html>
<head>
<title>SMTemplate Angular2 & ASP.NET Core</title>
<base href="/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
https://riptutorial.com/ 112
<script>
System.import('main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading AppComponent here ...</my-app>
</body>
</html>
@Component({
selector: 'my-app',
templateUrl: '/home/index',
})
export class AppComponent { nombre = 'Samuel Maícas'; }
1. Download seed
2. Run dotnet restore
3. Run npm install
Always. Enjoy.
https://github.com/SamML/CoreAngular000
How to: CALL ANGULAR 2 HTML/JS COMPONENT FROM ASP.NET Core CONTROLLER:
And load angular component in the html. Here we can decide if we want to work with same or
diferent module. Depends on situation.
wwwroot/html/About.html
<!DOCTYPE html>
<html>
<head>
<title>About Page</title>
<base href="/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../css/site.min.css" rel="stylesheet" type="text/css"/>
<script src="../node_modules/core-js/client/shim.min.js"></script>
https://riptutorial.com/ 113
<script src="../node_modules/zone.js/dist/zone.js"></script>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../systemjs.config.js"></script>
<script>
System.import('../main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<aboutpage>Loading AppComponent here ...</aboutpage>
</body>
</html>
How to: CALL ASP.NET Core Controller to show a MVC View with Angular2 support:
@Component({
selector: 'aboutpage',
templateUrl: '/home/about',
})
export class AboutComponent {
Read Configuring ASP.net Core application to work with Angular 2 and TypeScript online:
https://riptutorial.com/angular2/topic/9543/configuring-asp-net-core-application-to-work-with-
angular-2-and-typescript
https://riptutorial.com/ 114
Chapter 33: Create an Angular 2+ NPM
package
Introduction
Sometimes we need to share some component between some apps and publishing it in npm is
one of the best ways of doing this.
There are some tricks that we need to know to be able to use a normal component as npm
package without changing the structure as inlining external styles.
Examples
Simplest package
Here we are sharing some minimal workflow to build and publish an Angular 2+ npm package.
Configuration files
We need some config files to tell git, npm, gulp and typescript how to act.
.gitignore
First we create a .gitignore file to avoid versioning unwanted files and folders. The content is:
npm-debug.log
node_modules
jspm_packages
.idea
build
.npmignore
Second we create a .npmignore file to avoid publishing unwanted files and folders. The content is:
examples
node_modules
src
gulpfile.js
We need to create a gulpfile.js to tell Gulp how to compile our application. This part is necessary
https://riptutorial.com/ 115
because we need to minimize and inline all the external templates and styles before publishing our
package. The content is:
gulp.task('js:build', function () {
gulp.src('src/*.ts') // also can use *.js files
.pipe(embedTemplates({sourceType:'ts'}))
.pipe(inlineNg2Styles({ base: '/src' }))
.pipe(gulp.dest('./dist'));
});
index.d.ts
The index.d.ts file is used by typescript when importing an external module. It helps editor with
auto-completion and function tips.
index.js
This is the package entry point. When you install this package using NPM and import in your
application, you just need to pass the package name and your application will learn where to find
any EXPORTED component of your package.
exports.AngularXMinimalNpmPackageModule = require('./lib').AngularXMinimalNpmPackageModule;
We used lib folder because when we compile our code, the output is placed inside /lib folder.
package.json
This file is used to configure your npm publication and defines the necessary packages to it to
work.
{
"name": "angular-x-minimal-npm-package",
"version": "0.0.18",
"description": "An Angular 2+ Data Table that uses HTTP to create, read, update and delete
data from an external API such REST.",
"main": "index.js",
"scripts": {
"watch": "tsc -p src -w",
"build": "gulp js:build && rm -rf lib && tsc -p dist"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vinagreti/angular-x-minimal-npm-package.git"
},
"keywords": [
"Angular",
https://riptutorial.com/ 116
"Angular2",
"Datatable",
"Rest"
],
"author": "[email protected]",
"license": "MIT",
"bugs": {
"url": "https://github.com/vinagreti/angular-x-minimal-npm-package/issues"
},
"homepage": "https://github.com/vinagreti/angular-x-minimal-npm-package#readme",
"devDependencies": {
"gulp": "3.9.1",
"gulp-angular-embed-templates": "2.3.0",
"gulp-inline-ng2-styles": "0.0.1",
"typescript": "2.0.0"
},
"dependencies": {
"@angular/common": "2.4.1",
"@angular/compiler": "2.4.1",
"@angular/core": "2.4.1",
"@angular/http": "2.4.1",
"@angular/platform-browser": "2.4.1",
"@angular/platform-browser-dynamic": "2.4.1",
"rxjs": "5.0.2",
"zone.js": "0.7.4"
}
}
dist/tsconfig.json
Create a dist folder and place this file inside. This file is used to tell Typescript how to compile your
application. Where to to get the typescript folder and where to put the compiled files.
{
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"mapRoot": "",
"rootDir": ".",
"target": "es5",
"lib": ["es6", "es2015", "dom"],
"inlineSources": true,
"stripInternal": true,
"module": "commonjs",
"moduleResolution": "node",
"removeComments": true,
"sourceMap": true,
"outDir": "../lib",
"declaration": true
}
}
After create the configuration files, we must create our component and module. This component
receives a click and displays a message. It is used like a html tag <angular-x-minimal-npm-
package></angular-x-minimal-npm-package>. Just instal this npm package and load its module in the
model you want to use it.
https://riptutorial.com/ 117
src/angular-x-minimal-npm-package.component.ts
src/angular-x-minimal-npm-package.component.html
<div>
<h1 (click)="onClick()">{{message}}</h1>
</div>
src/angular-x-data-table.component.css
h1{
color: red;
}
src/angular-x-minimal-npm-package.module.ts
@NgModule({
imports: [ CommonModule ],
declarations: [ AngularXMinimalNpmPackageComponent ],
exports: [ AngularXMinimalNpmPackageComponent ],
entryComponents: [ AngularXMinimalNpmPackageComponent ],
})
export class AngularXMinimalNpmPackageModule {}
After that, you must compile, build and publish your package.
https://riptutorial.com/ 118
To build and compile, run the following command at the root of your package:
This will trigger the chain and you will end up with your build in /dist folder and the compiled
package in your /lib folder. This is why in index.js we exported the code from /lib folder and not
from /src.
Publish
Now we just need to publish our package so we can install it through npm. For that, just run the
command:
npm publish
That is all!!!
https://riptutorial.com/ 119
Chapter 34: Creating an Angular npm library
Introduction
How to publish your NgModule, written in TypeScript in npm registry. Setting up npm project,
typescript compiler, rollup and continous integration build.
Examples
Minimal module with service class
File structure
/
-src/
awesome.service.ts
another-awesome.service.ts
awesome.module.ts
-index.ts
-tsconfig.json
-package.json
-rollup.config.js
-.npmignore
src/awesome.service.ts:
src/awesome.module.ts:
@NgModule({
providers: [AwesomeService, AnotherAwesomeService]
})
export class AwesomeModule {}
https://riptutorial.com/ 120
Make your module and service accessible outside.
/index.ts:
Compilation
In compilerOptions.paths you need to specify all external modules which you used in your
package.
/tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"stripInternal": true,
"experimentalDecorators": true,
"strictNullChecks": false,
"noImplicitAny": true,
"module": "es2015",
"moduleResolution": "node",
"paths": {
"@angular/core": ["node_modules/@angular/core"],
"rxjs/*": ["node_modules/rxjs/*"]
},
"rootDir": ".",
"outDir": "dist",
"sourceMap": true,
"inlineSources": true,
"target": "es5",
"skipLibCheck": true,
"lib": [
"es2015",
"dom"
]
},
"files": [
"index.ts"
],
"angularCompilerOptions": {
"strictMetadataEmit": true
}
}
/rollup.config.js
export default {
entry: 'dist/index.js',
https://riptutorial.com/ 121
dest: 'dist/bundles/awesome.module.umd.js',
sourceMap: false,
format: 'umd',
moduleName: 'ng.awesome.module',
globals: {
'@angular/core': 'ng.core',
'rxjs': 'Rx',
'rxjs/Observable': 'Rx',
'rxjs/ReplaySubject': 'Rx',
'rxjs/add/operator/map': 'Rx.Observable.prototype',
'rxjs/add/operator/mergeMap': 'Rx.Observable.prototype',
'rxjs/add/observable/fromEvent': 'Rx.Observable',
'rxjs/add/observable/of': 'Rx.Observable'
},
external: ['@angular/core', 'rxjs']
}
NPM settings
Now, lets place some instructions for npm
/package.json
{
"name": "awesome-angular-module",
"version": "1.0.4",
"description": "Awesome angular module",
"main": "dist/bundles/awesome.module.umd.min.js",
"module": "dist/index.js",
"typings": "dist/index.d.ts",
"scripts": {
"test": "",
"transpile": "ngc",
"package": "rollup -c",
"minify": "uglifyjs dist/bundles/awesome.module.umd.js --screw-ie8 --compress --mangle --
comments --output dist/bundles/awesome.module.umd.min.js",
"build": "rimraf dist && npm run transpile && npm run package && npm run minify",
"prepublishOnly": "npm run build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/maciejtreder/awesome-angular-module.git"
},
"keywords": [
"awesome",
"angular",
"module",
"minimal"
],
"author": "Maciej Treder <[email protected]>",
"license": "MIT",
"bugs": {
"url": "https://github.com/maciejtreder/awesome-angular-module/issues"
},
"homepage": "https://github.com/maciejtreder/awesome-angular-module#readme",
"devDependencies": {
"@angular/compiler": "^4.0.0",
https://riptutorial.com/ 122
"@angular/compiler-cli": "^4.0.0",
"rimraf": "^2.6.1",
"rollup": "^0.43.0",
"typescript": "^2.3.4",
"uglify-js": "^3.0.21"
},
"dependencies": {
"@angular/core": "^4.0.0",
"rxjs": "^5.3.0"
}
}
/.npmignore
node_modules
npm-debug.log
Thumbs.db
.DS_Store
src
!dist/src
plugin
!dist/plugin
*.ngsummary.json
*.iml
rollup.config.js
tsconfig.json
*.ts
!*.d.ts
.idea
Continuous integration
Finally you can set up continuous integration build
.travis.yml
language: node_js
node_js:
- node
deploy:
provider: npm
email: [email protected]
api_key:
secure: <your api key>
on:
tags: true
repo: maciejtreder/awesome-angular-module
https://riptutorial.com/ 123
an-angular-npm-library
https://riptutorial.com/ 124
Chapter 35: CRUD in Angular2 with Restful
API
Syntax
• @Injectable() // Tells dependency injector to inject dependencies when creating instance of
this service.
• request.subscribe() // This is where you actually make the request. Without this your request
won't be sent. Also you want to read response in the callback function.
Examples
Read from an Restful API in Angular2
To separate API logic from the component, we are creating the API client as a separate class.
This example class makes a request to Wikipedia API to get random wiki articles.
@Injectable()
export class WikipediaService{
constructor(private http: Http) {}
getRandomArticles(numberOfArticles: number)
{
var request =
this.http.get("https://en.wikipedia.org/w/api.php?action=query&list=random&format=json&rnlimit="
+ numberOfArticles);
return request.map((response: Response) => {
return response.json();
},(error) => {
console.log(error);
//your want to implement your own error handling here.
});
}
}
https://riptutorial.com/ 125
@Component({
selector: 'wikipedia',
templateUrl: 'wikipedia.component.html'
})
export class WikipediaComponent implements OnInit {
constructor(private wikiService: WikipediaService) { }
https://riptutorial.com/ 126
Chapter 36: custom ngx-bootstrap datepicker
+ input
Examples
custom ngx-bootstrap datepicker
datepicker.component.html
datepicker.component.ts
@Component({
selector: 'custom-datepicker',
templateUrl: 'datepicker.component.html',
providers: [DatePipe, NgModel],
host: {
'(document:mousedown)': 'onClick($event)',
}
})
inputElement : ElementRef;
dt: Date = null;
showDatepicker: boolean = false;
https://riptutorial.com/ 127
@Input() disabledDatePicker: boolean = false;
@Input() value: string = null;
@Input() id: string;
@Input() min: Date = null;
@Input() max: Date = null;
changedDate(){
if(this.value === ''){
this.dateModelChange.emit(null);
}else if(this.value.split('/').length === 3){
this.dateModelChange.emit(DatepickerComponent.convertToDate(this.value));
}
}
clickOutSide(event : Event){
if(this.inputElement.nativeElement !== event.target) {
console.log('click outside', event);
}
}
onClick(event) {
if (!this.inputElement.nativeElement.contains(event.target)) {
this.close();
}
}
ngOnChanges(changes: SimpleChanges): void {
if (this.value !== null && this.value !== undefined && this.value.length > 0) {
this.value = null;
this.dt = null;
}else {
if(this.value !== null){
this.dt = new Date(this.value);
this.value = moment(this.value).format('MM/DD/YYYY');
}
}
}
openCloseDatepicker(): void {
if (!this.disabledDatePicker) {
this.showDatepicker = !this.showDatepicker;
}
}
open(): void {
this.showDatepicker = true;
}
close(): void {
this.showDatepicker = false;
}
https://riptutorial.com/ 128
this.value = DatepickerComponent.transformDate(this.dt);
this.dateModelChange.emit(this.dt);
}
https://riptutorial.com/ 129
Chapter 37: Debugging Angular2 typescript
application using Visual Studio Code
Examples
Launch.json setup for you workspace
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceRoot}"
],
"stopOnEntry": false,
"sourceMaps": true,
"outDir": "${workspaceRoot}/out",
"preLaunchTask": "npm"
}
]
}
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/app/main.js", // put your main.js path
"stopOnEntry": false,
"args": [],
"cwd": "${workspaceRoot}",
"preLaunchTask": null,
"runtimeExecutable": null,
https://riptutorial.com/ 130
"runtimeArgs": [
"--nolazy"
],
"env": {
"NODE_ENV": "development"
},
"console": "internalConsole",
"sourceMaps": false,
"outDir": null
},
{
"name": "Attach",
"type": "node",
"request": "attach",
"port": 5858,
"address": "localhost",
"restart": false,
"sourceMaps": false,
"outDir": null,
"localRoot": "${workspaceRoot}",
"remoteRoot": null
},
{
"name": "Attach to Process",
"type": "node",
"request": "attach",
"processId": "${command.PickProcess}",
"port": 5858,
"sourceMaps": false,
"outDir": null
}
]
}
3. Now it debug is working, show notification popup for step by step debugging
Read Debugging Angular2 typescript application using Visual Studio Code online:
https://riptutorial.com/angular2/topic/7139/debugging-angular2-typescript-application-using-visual-
studio-code
https://riptutorial.com/ 131
Chapter 38: Detecting resize events
Examples
A component listening in on the window resize event.
@Component({
...
template: `
<div>
<p [hidden]="!visible" (window:resize)="onResize($event)" >Now you see me...</p>
<p>now you dont!</p>
</div>
`
...
})
export class MyComponent {
visible: boolean = false;
breakpoint: number = 768;
constructor() {
}
onResize(event) {
const w = event.target.innerWidth;
if (w >= this.breakpoint) {
this.visible = true;
} else {
// whenever the window is less than 768, hide this component.
this.visible = false;
}
}
}
A p tag in our template will hide whenever visible is false. visible will change value whenever the
onResize event handler is invoked. Its call occurs every time window:resize fires an event.
https://riptutorial.com/ 132
Chapter 39: Directives
Syntax
• <input [value]="value"> - Binds attribute value class member name.
Remarks
The main source of information about Angular 2 directives is the official documentation
https://angular.io/docs/ts/latest/guide/attribute-directives.html
Examples
Attribute directive
<div [class.active]="isActive"></div>
<span [style.color]="'red'"></span>
Structural directives
<span *ngIf="isVisible"></span>
Custom directive
https://riptutorial.com/ 133
import {Directive, ElementRef, Renderer} from '@angular/core';
@Directive({
selector: '[green]',
})
class GreenDirective {
constructor(private _elementRef: ElementRef,
private _renderer: Renderer) {
_renderer.setElementStyle(_elementRef.nativeElement, 'color', 'green');
}
}
Usage:
*ngFor
form1.component.ts:
Output:
<div>Apples</div>
<div>Oranges</div>
<div>Bananas</div>
<div>Limes</div>
<div>Lemons</div>
<select required>
<option value="Apples">Apples</option>
<option value="Oranges">Oranges</option>
<option value="Bananas">Bananas</option>
<option value="Limes">Limes</option>
<option value="Lemons">Lemons</option>
</select>
In its most simple form, *ngFor has two parts : let variableName of object/array
https://riptutorial.com/ 134
In the case of fruit = ['Apples', 'Oranges', 'Bananas', 'Limes', 'Lemons'];,
Apples, Oranges, and so on are the values inside the array fruit.
[value]="f" will be equal to each current fruit (f) that *ngFor has iterated over.
Unlike AngularJS, Angular2 has not continued with the use of ng-options for <select> and ng-repeat
for all other general repetitions.
References:
Angular2 | ngFor
Angular2 | Forms
In this example we are going to create a directive to copy a text into the clipboard by clicking on an
element
copy-text.directive.ts
import {
Directive,
Input,
HostListener
} from "@angular/core";
@Directive({
selector: '[text-copy]'
})
export class TextCopyDirective {
constructor() {
}
// The HostListener will listen to click events and run the below function, the
HostListener supports other standard events such as mouseenter, mouseleave etc.
@HostListener('click') copyText() {
// We need to create a dummy textarea with the text to be copied in the DOM
var textArea = document.createElement("textarea");
https://riptutorial.com/ 135
textArea.style.width = '2em';
textArea.style.height = '2em';
textArea.style.padding = '0';
textArea.style.border = 'none';
textArea.style.outline = 'none';
textArea.style.boxShadow = 'none';
textArea.style.background = 'transparent';
// Set the texarea's content to our value defined in our [text-copy] attribute
textArea.value = this.text;
document.body.appendChild(textArea);
try {
// Most modern browsers support execCommand('copy'|'cut'|'paste'), if it doesn't
it should throw an error
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
// Let the user know the text has been copied, e.g toast, alert etc.
console.log(msg);
} catch (err) {
// Tell the user copying is not supported and give alternative, e.g alert window
with the text to copy
console.log('unable to copy');
}
some-page.component.html
...
<!-- Insert variable as the attribute's value, let textToBeCopied = 'http://facebook.com/'
-->
<button [text-copy]="textToBeCopied">Copy URL</button>
<button [text-copy]="'https://www.google.com/'">Copy URL</button>
...
https://riptutorial.com/ 136
constructor(private el: ElementRef) { }
@HostListener('mouseenter')
onMouseEnter() {
this.highlight(this.highlightColor || 'red');
}
@HostListener('mouseleave')
onMouseLeave() {
this.highlight(null);
}
@Component({
selector: 'app-test-container',
template: `
<div>
<span id="red" appHighlight>red text</span>
<span id="green" [appHighlight]="'green'">green text</span>
<span id="no">no color</span>
</div>
`
})
class ContainerComponent { }
const mouseEvents = {
get enter() {
const mouseenter = document.createEvent('MouseEvent');
mouseenter.initEvent('mouseenter', true, true);
return mouseenter;
},
get leave() {
const mouseleave = document.createEvent('MouseEvent');
mouseleave.initEvent('mouseleave', true, true);
return mouseleave;
},
};
describe('HighlightDirective', () => {
let fixture: ComponentFixture<ContainerComponent>;
let container: ContainerComponent;
let element: HTMLElement;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ContainerComponent, HighlightDirective],
providers: [
{ provide: ComponentFixtureAutoDetect, useValue: true },
],
https://riptutorial.com/ 137
});
fixture = TestBed.createComponent(ContainerComponent);
// fixture.detectChanges(); // without the provider
container = fixture.componentInstance;
element = fixture.nativeElement;
});
it('should set background-color to empty when mouse leaves with directive without
arguments', () => {
const targetElement = <HTMLSpanElement>element.querySelector('#red');
targetElement.dispatchEvent(mouseEvents.leave);
expect(targetElement.style.backgroundColor).toEqual('');
});
it('should set background-color to empty when mouse leaves with directive with arguments',
() => {
const targetElement = <HTMLSpanElement>element.querySelector('#green');
targetElement.dispatchEvent(mouseEvents.leave);
expect(targetElement.style.backgroundColor).toEqual('');
});
targetElement.dispatchEvent(mouseEvents.enter);
expect(targetElement.style.backgroundColor).toEqual('red');
});
targetElement.dispatchEvent(mouseEvents.enter);
expect(targetElement.style.backgroundColor).toEqual('green');
});
});
https://riptutorial.com/ 138
Chapter 40: Directives & components :
@Input @Output
Syntax
1. One way binding from parent component to nested component: [propertyName]
2. One way binding from nested component to parent component: (propertyName)
3. Two-way binding (a.k.a banana box notation) : [(propertyName)]
Examples
Input example
Let's say that the selector of your component is 'car-component', when you call the component,
add the attribute 'car'
<car-component [car]="car"></car-component>
Full Example :
1. car.entity.ts
2. car.component.ts
@Component({
https://riptutorial.com/ 139
selector: 'car-component',
template: require('./templates/car.html'),
})
constructor() {
console.log('gros');
}
}
3. garage.component.ts
@Component({
selector: 'garage',
template: require('./templates/garage.html'),
directives: [CarComponent]
})
constructor() {
var carOne : CarEntity = new CarEntity('renault', 'blue');
var carTwo : CarEntity = new CarEntity('fiat', 'green');
var carThree : CarEntity = new CarEntity('citroen', 'yellow');
this.cars = [carOne, carTwo, carThree];
}
}
4. garage.html
5. car.html
<div>
<span>{{ car.brand }}</span> |
<span>{{ car.color }}</span>
</div>
A Button directive which accepts an @Input() to specify a click limit until the button gets disabled.
The parent component can listen to an event which will be emitted when the click limit is reached
via @Output:
https://riptutorial.com/ 140
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'limited-button',
template: `<button (click)="onClick()"
[disabled]="disabled">
<ng-content></ng-content>
</button>`,
directives: []
})
onClick() {
this.clickCount++;
if (this.clickCount === this.clickLimit) {
this.disabled = true;
this.limitReached.emit(this.clickCount);
}
}
}
Parent component which uses the Button directive and alerts a message when the click limit is
reached:
@Component({
selector: 'my-parent-component',
template: `<limited-button [clickLimit]="2"
(limitReached)="onLimitReached($event)">
You can only click me twice
</limited-button>`,
directives: [LimitedButton]
})
Sometimes you need to fetch data asynchronously before passing it to a child component to use.
If the child component tries to use the data before it has been received, it will throw an error. You
can use ngOnChanges to detect changes in a components' @Inputs and wait until they are defined
before acting upon them.
https://riptutorial.com/ 141
Parent component with async call to an
endpoint
import { Component, OnChanges, OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ChildComponent } from './child.component';
@Component ({
selector : 'parent-component',
template : `
<child-component [data]="asyncData"></child-component>
`
})
export class ParentComponent {
asyncData : any;
constructor(
private _http : Http
){}
ngOnInit () {
this._http.get('some.url')
.map(this.extractData)
.subscribe(this.handleData)
.catch(this.handleError);
}
extractData (res:Response) {
let body = res.json();
return body.data || { };
}
handleData (data:any) {
this.asyncData = data;
}
handleError (error:any) {
console.error(error);
}
}
https://riptutorial.com/ 142
@Component ({
selector : 'child-component',
template : `
<p *ngIf="doesDataExist">Hello child</p>
`
})
export class ChildComponent {
https://riptutorial.com/ 143
Chapter 41: Dropzone in Angular2
Examples
Dropzone
@NgModule({
...
imports: [
...
DropzoneModule.forRoot(DROPZONE_CONFIG)
]
})
COMPONENT USAGE
Simply replace the element that would oridinarily be passed to Dropzone with the
dropzone component.
onUploadError(args: any) {
console.log('onUploadError:', args);
}
https://riptutorial.com/ 144
onUploadSuccess(args: any) {
console.log('onUploadSuccess:', args);
}
}
https://riptutorial.com/ 145
Chapter 42: Dynamically add components
using ViewContainerRef.createComponent
Examples
A wrapper component that adds dynamic components declaratively
A custom component that takes the type of a component as input and creates an instance of that
component type inside itself. When the input is updated, the previously added dynamic component
is removed and the new one added instead.
@Component({
selector: 'dcl-wrapper',
template: `<div #target></div>`
})
export class DclWrapper {
@ViewChild('target', {
read: ViewContainerRef
}) target;
@Input() type;
cmpRef: ComponentRef;
private isViewInitialized: boolean = false;
updateComponent() {
if (!this.isViewInitialized) {
return;
}
if (this.cmpRef) {
this.cmpRef.destroy();
}
this.resolver.resolveComponent(this.type).then((factory: ComponentFactory < any > ) => {
this.cmpRef = this.target.createComponent(factory)
// to access the created instance use
// this.cmpRef.instance.someProperty = 'someValue';
// this.cmpRef.instance.someOutput.subscribe(val => doSomething());
});
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
https://riptutorial.com/ 146
}
<dcl-wrapper [type]="someComponentType"></dcl-wrapper>
Plunker example
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<input type="button" value="Click me to add element" (click) = addElement()> // call the
function on click of the button
<div #parent> </div> // Dynamic component will be loaded here
</div>
`,
})
export class App {
name:string;
addElement(){
let childComponent =
this.componentFactoryResolver.resolveComponentFactory(ChildComponent);
this.componentRef = this.target.createComponent(childComponent);
}
}
childComp.ts :
@Component({
selector: 'child',
template: `
<p>This is Child</p>
`,
})
https://riptutorial.com/ 147
export class ChildComponent {
constructor(){
}
}
app.module.ts :
@NgModule({
imports: [ BrowserModule ],
declarations: [ App, ChildComponent ],
bootstrap: [ App ],
entryComponents: [ChildComponent] // define the dynamic component here in module.ts
})
export class AppModule {}
Plunker example
We can create dynamic component and get the instances of component into an array and finally
rendered it on template.
For example, we can can consider two widget component, ChartWidget and PatientWidget which
extended the class WidgetComponent that I wanted to add in the container.
ChartWidget.ts
@Component({
selector: 'chart-widget',
templateUrl: 'chart-widget.component.html',
providers: [{provide: WidgetComponent, useExisting: forwardRef(() => ChartWidget) }]
})
<p-panel [style]="{'margin-bottom':'20px'}">
<p-header>
<div class="ui-helper-clearfix">
<span class="ui-panel-title" style="font-size:14px;display:inline-block;margin-
top:2px">Chart Widget</span>
https://riptutorial.com/ 148
<div class="ui-toolbar-group-right">
<button pButton type="button" icon="fa-window-minimize"
(click)="minimize()"</button>
<button pButton type="button" icon="fa-refresh" (click)="refresh()"></button>
<button pButton type="button" icon="fa-expand" (click)="expand()" ></button>
<button pButton type="button" (click)="close()" icon="fa-window-close"></button>
</div>
</div>
</p-header>
some data
</p-panel>
DataWidget.ts
@Component({
selector: 'data-widget',
templateUrl: 'data-widget.component.html',
providers: [{provide: WidgetComponent, useExisting: forwardRef(() =>DataWidget) }]
})
WidgetComponent.ts
@Component({
selector: 'widget',
template: '<ng-content></ng-content>'
})
export class WidgetComponent{
}
we can creat dynamic component instances by selecting the pre-existing components. For
example,
@Component({
selector: 'dynamic-component',
template: `<div #container><ng-content></ng-content></div>`
})
export class DynamicComponent {
@ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef;
https://riptutorial.com/ 149
public addComponent(ngItem: Type<WidgetComponent>): WidgetComponent {
let factory = this.compFactoryResolver.resolveComponentFactory(ngItem);
const ref = this.container.createComponent(factory);
const newItem: WidgetComponent = ref.instance;
this._elements.push(newItem);
return newItem;
}
}
@Component({
selector: 'app-root',
templateUrl: './app/app.component.html',
styleUrls: ['./app/app.component.css'],
entryComponents: [ChartWidget, DataWidget],
})
this.dynamicComponent.resetContainer();
}
}
app.component.html
<hr>
Dynamic Components
<hr>
<widget *ngFor="let item of elements">
<div>{{item}}</div>
<div [innerHTML]="item._ngEl.nativeElement.innerHTML | sanitizeHtml">
</div>
</widget>
https://plnkr.co/edit/lugU2pPsSBd3XhPHiUP1?p=preview
view.directive.ts
https://riptutorial.com/ 150
import { ViewRef, Directive, Input, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[view]'
})
export class ViewDirective {
constructor(private vcRef: ViewContainerRef) {}
@Input()
set view(view: ViewRef) {
this.vcRef.clear();
this.vcRef.insert(view);
}
ngOnDestroy() {
this.vcRef.clear()
}
}
app.component.ts
...
addComponent(widget: string ): void{
let component = this.dynamicComponent.addComponent(this.WidgetClasses[widget]);
let view: ViewRef = this.dynamicComponent.container.detach(0);
this.elements.push({view,component});
this.dynamicComponent.resetContainer();
}
app.component.html
https://plnkr.co/edit/JHpIHR43SvJd0OxJVMfV?p=preview
https://riptutorial.com/ 151
Chapter 43: EventEmitter Service
Examples
Class Overview
Class Component
@Component({
selector: 'zippy',
template: `
<div class="zippy">
<div (click)="toggle()">Toggle</div>
<div [hidden]="!visible">
<ng-content></ng-content>
</div>
</div>`})
export class Zippy {
visible: boolean = true;
@Output() open: EventEmitter<any> = new EventEmitter();
@Output() close: EventEmitter<any> = new EventEmitter();
toggle() {
this.visible = !this.visible;
if (this.visible) {
this.open.emit(null);
} else {
this.close.emit(null);
}
}
}
Emmiting Events
Create a service-
https://riptutorial.com/ 152
}
getNavChangeEmitter() {
return this.navchange;
}
}
@Component({
selector: 'obs-comp',
template: `obs component, item: {{item}}`
})
export class ObservingComponent {
item: number = 0;
subscription: any;
constructor(private navService:NavService) {}
ngOnInit() {
this.subscription = this.navService.getNavChangeEmitter()
.subscribe(item => this.selectedNavItem(item));
}
selectedNavItem(item: number) {
this.item = item;
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@Component({
selector: 'my-nav',
template:`
<div class="nav-item" (click)="selectedNavItem(1)">nav 1 (click me)</div>
<div class="nav-item" (click)="selectedNavItem(2)">nav 2 (click me)</div>
`,
})
export class Navigation {
item = 1;
constructor(private navService:NavService) {}
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this.navService.emitNavChangeEvent(item);
}
}
Live example
https://riptutorial.com/ 153
Chapter 44: Example for routes such as
/route/subroute for static urls
Examples
Basic route example with sub routes tree
app.module.ts
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, mainModule.forRoot(), RouterModule.forRoot(routes)],
providers: [],
bootstrap: [AppComponent]
})
app.routes.ts
subTreeRoutes.ts
Read Example for routes such as /route/subroute for static urls online:
https://riptutorial.com/angular2/topic/8910/example-for-routes-such-as--route-subroute-for-static-
urls
https://riptutorial.com/ 154
Chapter 45: Feature Modules
Examples
A Feature Module
// my-feature.module.ts
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
@NgModule({
imports: [ CommonModule ],
declarations: [ MyComponent, MyDirective, MyPipe ],
exports: [ MyComponent ],
providers: [ MyService ]
})
export class MyFeatureModule { }
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
// import MyFeatureModule in root module
imports: [ BrowserModule, MyFeatureModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
https://riptutorial.com/ 155
Chapter 46: How to use ngfor
Introduction
The ngFor directive is used by Angular2 to instantiate a template once for every item in an iterable
object. This directive binds the iterable to the DOM, so if the content of the iterable changes, the
content of the DOM will be also changed.
Examples
Unordered list example
<ul>
<li *ngFor="let item of items">{{item.name}}</li>
</ul>
In this case, i will take the value of index, which is the current loop iteration.
Angular2 provides several exported values that can be aliased to local variables. These are:
• index
• first
• last
• even
• odd
Except index, the other ones take a Boolean value. As the previous example using index, it can be
used any of these exported values:
https://riptutorial.com/ 156
<div *ngFor="let item of items; let firstItem = first; let lastItem = last">
<p *ngIf="firstItem">I am the first item and I am gonna be showed</p>
<p *ngIf="firstItem">I am not the first item and I will not show up :(</p>
<p *ngIf="lastItem">But I'm gonna be showed as I am the last item :)</p>
</div>
@Component({
selector: 'example-component',
template: '<div>
<div *ngFor="let number of numbers | even">
{{number}}
</div>
</div>'
})
https://riptutorial.com/ 157
Chapter 47: How to Use ngif
Introduction
*NgIf: It removes or recreates a part of DOM tree depending on an expression evaluation. It is a
structural directive and structural directives alter the layout of the DOM by adding, replacing and
removing its elements.
Syntax
• <div *ngIf="false"> test </div> <!-- evaluates to false -->
• <div *ngIf="undefined"> test </div> <!-- evaluates to false -->
• <div *ngIf="null"> test </div> <!-- evaluates to false -->
• <div *ngIf="0"> test </div> <!-- evaluates to false -->
• <div *ngIf="NaN"> test </div> <!-- evaluates to false -->
• <div *ngIf=""> test </div> <!-- evaluates to false -->
• All other values evaluate to true.
Examples
Display a loading message
If our component is not ready and waiting for data from server, then we can add loader using *ngIf.
Steps:
ngOnInit() {
this.loading = true;
}
and after you get complete data from server set you loading boolean to false.
this.loading=false;
https://riptutorial.com/ 158
Show Alert Message on a condition
<p class="alert alert-success" *ngIf="names.length > 2">Currently there are more than 2
names!</p>
While you are not allowed to use *ngIf and *ngFor in the same div (it will gives an error in the
runtime) you can nest the *ngIf in the *ngFor to get the desired behavior.
</div>
</div>
But consider this use case where a div element needs to be iterated (using *ngFor) and also
includes a check whether the element need to be removed or not (using *ngIf), but adding an
https://riptutorial.com/ 159
additional div is not preferred. In this case you can use the template tag for the *ngFor:
This way adding an additional outer div is not needed and furthermore the <template> element
won't be added to the DOM. The only elements added in the DOM from the above example are
the iterated div elements.
Note: In Angular v4 <template> has been deprecated in favour of <ng-template> and will be removed
in v5. In Angular v2.x releases <template> is still valid.
https://riptutorial.com/ 160
Chapter 48: Http Interceptor
Remarks
What we do with HttpServiceLayer class is extend the Http class from angular and add our own
logic to it.
We then inject that class in the bootstrap class of the application and tell angular that were we
import the Http class, in the back to insert the HttpServiceLayer.
Examples
Simple Class Extending angular's Http class
/**
* This class extends the Http class from angular and adds automaticaly the server URL(if in
development mode) and 2 headers by default:
* Headers added: 'Content-Type' and 'X-AUTH-TOKEN'.
* 'Content-Type' can be set in any othe service, and if set, it will NOT be overwritten in
this class any more.
*/
export class HttpServiceLayer extends Http {
/**
* This method checks if there are any headers added and if not created the headers map and
ads 'Content-Type' and 'X-AUTH-TOKEN'
https://riptutorial.com/ 161
* 'Content-Type' is not overwritten if it is allready available in the headers map
*/
getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
if (options == null) {
options = new RequestOptions();
}
if (options.headers == null) {
options.headers = new Headers();
}
if (!options.headers.get('Content-Type')) {
options.headers.append('Content-Type', 'application/json');
}
if (this.appConfig.getAuthToken() != null) {
options.headers.append('X-AUTH-TOKEN', this.appConfig.getAuthToken());
}
return options;
}
/**
* This method as the name sugests intercepts the request and checks if there are any errors.
* If an error is present it will be checked what error there is and if it is a general one
then it will be handled here, otherwise, will be
* thrown up in the service layers
*/
intercept(observable: Observable<Response>): Observable<Response> {
// return observable;
return observable.catch((err, source) => {
if (err.status == 401) {
this._router.navigate(['/login']);
//return observable;
return Observable.empty();
} else {
//return observable;
return Observable.throw(err);
}
});
}
}
After extending the Http class, we need to tell angular to use this class instead of Http class.
In order to do this, in our main module(or depending on the needs, just a particular module), we
need to write in the providers section:
https://riptutorial.com/ 162
@NgModule({
declarations: [ ... ],
imports: [ ... ],
exports: [ ... ],
providers: [
ApplicationConfiguration,
{
provide: Http,
useFactory: httpServiceFactory,
deps: [XHRBackend, RequestOptions, Router, ApplicationConfiguration]
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
Note: ApplicationConfiguration is just a service I use to hold some values for the duration of the
application
@Injectable()
export class AuthHeaderInterceptor implements HttpInterceptor {
https://riptutorial.com/ 163
Chapter 49: Installing 3rd party plugins with
[email protected]
Remarks
It is possible to install other libraries following, this approach, however, there might be a need to
specify the module type, main file, and default extension.
'lodash': {
format: 'cjs',
defaultExtension: 'js',
main: 'index.js'
}
'moment': {
main: 'moment.js'
}
Examples
Adding jquery library in angular-cli project
This is required so the build system will pick up the file. After setup the angular-cli-build.js
should look like this:
Browse the node_modules and look for files and folders you want to add to the vendor
folder.
module.exports = function(defaults) {
return new Angular2App(defaults, {
https://riptutorial.com/ 164
vendorNpmFiles: [
// ...
'jquery/dist/*.js'
]
});
};
};
or
and
@Component({
https://riptutorial.com/ 165
})
export class YourComponent {
ngOnInit() {
$.("button").click(function(){
// now you can DO, what ever you want
});
console.log();
}
}
If you followed the steps correctly you should now have jquery library working in your project.
Enjoy!
Some libraries or plugins may not have typings. Without these, TypeScript can't type check them
and therefore causes compilation errors. These libraries can still be used but differently than
imported modules.
• These scripts should add a global (eg. THREE, mapbox, $, etc.) or attach to a global
2. In the component that requires these, use declare to initialize a variable matching the global
name used by the lib. This lets TypeScript know that it has already been initialized. 1
Some libs attach to window, which would need to be extended in order to be accessible in the
app.
@Component { ... }
export class AppComponent implements AfterViewInit {
...
ngAfterViewInit() {
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
window.Intercom('boot', { ... }
}
}
• NOTE: Some libs may interact with the DOM and should be used in the appropriate
component lifecycle method.
https://riptutorial.com/ 166
Read Installing 3rd party plugins with [email protected] online:
https://riptutorial.com/angular2/topic/2328/installing-3rd-party-plugins-with-angular-cli-1-0-0-beta-
10
https://riptutorial.com/ 167
Chapter 50: Lazy loading a module
Examples
Lazy loading example
Lazy loading modules helps us decrease the startup time. With lazy loading our application does
not need to load everything at once, it only needs to load what the user expects to see when the
app first loads. Modules that are lazily loaded will only be loaded when the user navigates to their
routes.
app/app.module.ts
app/app.component.ts
app/app.routing.ts
https://riptutorial.com/ 168
{ path: 'eager', component: EagerComponent },
{ path: 'lazy', loadChildren: './lazy.module' }
];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes);
app/eager.component.ts
There's nothing special about LazyModule other than it has its own routing and a component
called LazyComponent (but it's not necessary to name your module or simliar so).
app/lazy.module.ts
app/lazy.routing.ts
app/lazy.component.ts
https://riptutorial.com/ 169
Chapter 51: Lifecycle Hooks
Remarks
Events availability
AfterViewInit and AfterViewChecked are only available in Components, and not in Directives.
Events order
• OnChanges (multiple times)
• OnInit (once)
• DoCheck (multiple times)
• AfterContentInit (once)
• AfterContentChecked (multiple times)
• AfterViewInit (once) (Component only)
• AfterViewChecked (multiple times) (Component only)
• OnDestroy (once)
Further Reading
• Angular Documentation - Lifecycle Hooks
Examples
OnInit
@Component({
selector: 'so-oninit-component',
templateUrl: 'oninit-component.html',
styleUrls: ['oninit-component.']
})
class OnInitComponent implements OnInit {
ngOnInit(): void {
console.log('Component is ready !');
}
}
https://riptutorial.com/ 170
OnDestroy
@Component({
selector: 'so-ondestroy-component',
templateUrl: 'ondestroy-component.html',
styleUrls: ['ondestroy-component.']
})
class OnDestroyComponent implements OnDestroy {
ngOnDestroy(): void {
console.log('Component was destroyed !');
}
}
OnChanges
Fired when one or more of the component or directive properties have been changed.
@Component({
selector: 'so-onchanges-component',
templateUrl: 'onchanges-component.html',
styleUrls: ['onchanges-component.']
})
class OnChangesComponent implements OnChanges {
@Input() name: string;
message: string;
name: {
currentValue: 'new name value',
previousValue: 'old name value'
},
message: {
currentValue: 'new message value',
previousValue: 'old message value'
}
AfterContentInit
Fire after the initialization of the content of the component or directive has finished.
https://riptutorial.com/ 171
import { Component, AfterContentInit } from '@angular/core';
@Component({
selector: 'so-aftercontentinit-component',
templateUrl: 'aftercontentinit-component.html',
styleUrls: ['aftercontentinit-component.']
})
class AfterContentInitComponent implements AfterContentInit {
ngAfterContentInit(): void {
console.log('Component content have been loaded!');
}
}
AfterContentChecked
@Component({
selector: 'so-aftercontentchecked-component',
templateUrl: 'aftercontentchecked-component.html',
styleUrls: ['aftercontentchecked-component.']
})
class AfterContentCheckedComponent implements AfterContentChecked {
ngAfterContentChecked(): void {
console.log('Component content have been checked!');
}
}
AfterViewInit
Fires after initializing both the component view and any of its child views. This is a useful lifecycle
hook for plugins outside of the Angular 2 ecosystem. For example, you could use this method to
initialize a jQuery date picker based on the markup that Angular 2 has rendered.
@Component({
selector: 'so-afterviewinit-component',
templateUrl: 'afterviewinit-component.html',
styleUrls: ['afterviewinit-component.']
})
class AfterViewInitComponent implements AfterViewInit {
ngAfterViewInit(): void {
console.log('This event fire after the content init have been loaded!');
}
}
AfterViewChecked
https://riptutorial.com/ 172
Fire after the check of the view, of the component, has finished.
@Component({
selector: 'so-afterviewchecked-component',
templateUrl: 'afterviewchecked-component.html',
styleUrls: ['afterviewchecked-component.']
})
class AfterViewCheckedComponent implements AfterViewChecked {
ngAfterViewChecked(): void {
console.log('This event fire after the content have been checked!');
}
}
DoCheck
@Component({
selector: 'so-docheck-component',
templateUrl: 'docheck-component.html',
styleUrls: ['docheck-component.']
})
class DoCheckComponent implements DoCheck {
@Input() elements: string[];
differ: any;
ngDoCheck(): void {
// get value for elements property
const changes = this.differ.diff(this.elements);
if (changes) {
changes.forEachAddedItem(res => console.log('Added', r.item));
changes.forEachRemovedItem(r => console.log('Removed', r.item));
}
}
}
https://riptutorial.com/ 173
Chapter 52: Mocking @ngrx/Store
Introduction
@ngrx/Store is becoming more widely used in Angular 2 projects. As such, the Store is required to
be injected into the constructor of any Component or Service that wishes to use it. Unit testing
Store isn't as easy as testing a simple service though. As with many problems, there are a myriad
of ways to implement solutions. However, the basic recipe is to write a mock class for the
Observer interface and to write a mock class for Store. Then you can inject Store as a provider in
your TestBed.
Parameters
name description
error description
super description
action$ mock Observer that does nothing unless defined to do so in the mock class
actionReducer$ mock Observer that does nothing unless defined to do so in the mock class
Remarks
Observer is a generic, but must be of type any to avoid unit testing complexity. The reason for this
complexity, is that Store's constructor expects Observer arguments with different generic types.
Using any avoids this complication.
It's possible to pass null values into StoreMock's super constructor, but this restricts the number of
assertions that can be used to test the class further down the road.
The Component being used in this example is just being used as context for how one would go
about injecting Store as a provide in the test setup.
Examples
Observer Mock
https://riptutorial.com/ 174
class ObserverMock implements Observer<any> {
closed?: boolean = false; // inherited from Observer
nextVal: any = ''; // variable I made up
constructor() {}
describe('Component:Typeahead', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [...],
declarations: [Typeahead],
providers: [
{provide: Store, useClass: StoreMock} // NOTICE useClass instead of useValue
]
}).compileComponents();
});
});
This is a unit test of a component that has Store as a dependency. Here, we are creating a new
class called MockStore that is injected into our component instead of the usual Store.
class MockStore {
public dispatch(obj) {
console.log('dispatching from the mock store!')
}
public select(obj) {
console.log('selecting from the mock store!');
return Observable.of({})
}
https://riptutorial.com/ 175
}
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
SmartComponentComponent,
DumbComponentComponent,
],
imports: [
StoreModule.provideStore({mainReducer})
],
providers: [
{provide: Store, useClass: MockStore}
]
});
});
This is a unit test of a component that has Store as a dependency. Here, we are able to use a
store with the default "initial state" while preventing it from actually dispatching actions when
store.dispatch() is called.
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
SmartComponentComponent,
DumbComponentComponent,
],
imports: [
StoreModule.provideStore({mainReducer})
]
});
});
https://riptutorial.com/ 176
it('should create the app', async(() => {
let fixture = TestBed.createComponent(AppComponent);
let app = fixture.debugElement.componentInstance;
}));
});
service
@Injectable()
export class PostService {
Component
• I created component with result parameter and postExample function that call to
postService.
• when the post resquest successed than result parameter should be 'Success' else 'Fail'
@Component({
selector: 'app-post',
templateUrl: './post.component.html',
styleUrls: ['./post.component.scss'],
providers : [PostService]
https://riptutorial.com/ 177
})
export class PostComponent{
test service
• when you want to test service that using http you should use mockBackend. and inject it to it.
• you need also to inject postService.
service
.postRequest(PostModel)
.subscribe((response) => {
expect(response).toBeDefined();
https://riptutorial.com/ 178
});
}));
});
test component
let mockRouter = {
navigate: jasmine.createSpy('navigate')
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [PostComponent],
imports: [RouterTestingModule.withRoutes([]),ModalModule.forRoot() ],
providers: [PostService ,MockBackend,BaseRequestOptions,
{provide: Http, deps: [MockBackend, BaseRequestOptions],
useFactory: (backend: XHRBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}
},
{provide: Router, useValue: mockRouter}
],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PostComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
component.postExample();
let postModel = new PostModel();
let response = {
'message' : 'message',
'ok' : true
};
mockBackend.connections.subscribe((connection: MockConnection) => {
postComponent.result = 'Success'
connection.mockRespond(new Response(
new ResponseOptions({
body: response
})
))
https://riptutorial.com/ 179
});
service.postRequest(postModel)
.subscribe((data) => {
expect(component.result).toBeDefined();
expect(PostComponent.result).toEqual('Success');
expect(data).toEqual(response);
});
}));
});
Simple Store
simple.action.ts
simple.efficts.ts
@Injectable()
export class simpleEffects {
@Effect()
addAction$: Observable<simpleAction> = this.actions$
.ofType(simpleActionTpye.add)
.switchMap((action: simpleAction) => {
console.log(action);
simple.reducer.ts
https://riptutorial.com/ 180
import { Action, ActionReducer } from '@ngrx/store';
store/index.ts
app.module.ts
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
// store
store,
effects
],
providers: [],
https://riptutorial.com/ 181
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
result 0 1 3 6
https://riptutorial.com/ 182
Chapter 53: Modules
Introduction
Angular modules are containers for different parts of your app.
You can have nested modules, your app.module is already actually nesting other modules such as
BrowserModule and you can add RouterModule and so on.
Examples
A simple module
A module is a class with the @NgModule decorator. To create a module we add @NgModule passing
some parameters:
• bootstrap: The component that will be the root of your application. This configuration is only
present on your root module
• declarations: Resources the module declares. When you add a new component you have to
update the declarations (ng generate component does it automatically)
• exports: Resources the module exports that can be used in other modules
• imports: Resources the module uses from other modules (only module classes are accepted)
• providers: Resources that can be injected (di) in a component
A simple example:
@NgModule({
bootstrap: [AppComponent]
declarations: [AppComponent],
exports: [],
imports: [BrowserModule],
providers: [],
})
export class AppModule { }
Nesting modules
We can create a core.module in our application that will contain generic things, like a ReservePipe (a
pipe that reverse a string) and bundle those in this module:
https://riptutorial.com/ 183
import { ReversePipe } from '../reverse.pipe';
@NgModule({
imports: [
CommonModule
],
exports: [ReversePipe], // export things to be imported in another module
declarations: [ReversePipe],
})
export class CoreModule { }
@NgModule({
declarations: [...], // ReversePipe is available without declaring here
// because CoreModule exports it
imports: [
CoreModule, // import things from CoreModule
...
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
https://riptutorial.com/ 184
Chapter 54: ngrx
Introduction
Ngrx is a powerful library that you can use with Angular2. The idea behind is to merge two
concepts that plays well together to have a reactive app with a predictable state container : -
[Redux][1] - [RxJs][2] The main advantages : - Sharing data in your app between your components
is going to easier - Testing your app core logic consists to test pure functions, without any
dependency on Angular2 (very easy so !) [1]: http://redux.js.org [2]: http://reactivex.io/rxjs
Examples
Complete example : Login/logout a user
Prerequisites
First, let's define an example from the very beginning and play with some code :
As a developer, I want to :
Spoiler alert : If you want to try the demo right away or read the code before we even get started,
here's a Plunkr (embed view or run view).
user.interface.ts
https://riptutorial.com/ 185
export interface IUser {
// from server
username: string;
email: string;
// for UI
isConnecting: boolean;
isConnected: boolean;
};
Now we've got to think about what kind of actions our reducers are supposed to handle.
Let say here :
user.actions.ts
But before we use those actions, let me explain why we're going to need a service to dispatch
some of those actions for us :
Let say that we want to connect a user. So we'll be clicking on a login button and here's what's
going to happen :
user.service.ts
@Injectable()
export class UserService {
constructor(public store$: Store<AppState>) { }
login(username: string) {
// first, dispatch an action saying that the user's tyring to connect
// so we can lock the button until the HTTP request finish
https://riptutorial.com/ 186
this.store$.dispatch({ type: UserActions.USR_IS_CONNECTING });
logout() {
// first, dispatch an action saying that the user's tyring to connect
// so we can lock the button until the HTTP request finish
this.store$.dispatch({ type: UserActions.USR_IS_DISCONNECTING });
user.state.ts
// for UI
isConnecting: false,
isConnected: false,
isDisconnecting: false
};
};
https://riptutorial.com/ 187
As we defined the default state of our reducer in part 3), we'll be able to use it like that :
user.reducer.ts
// ...
}
Hopefully, there's an easier way to write that by using our factory function to return an object and
within the reducer use an (ES6) default parameters value :
Then, we need to handle every actions in our reducer : TIP: Use ES6 Object.assign function to
keep our state immutable
case UserActions.USR_IS_CONNECTED:
return Object.assign({}, user, { isConnecting: false, isConnected: true, username:
action.payload.username });
case UserActions.USR_IS_DISCONNECTING:
return Object.assign({}, user, { isDisconnecting: true });
case UserActions.USR_IS_DISCONNECTED:
return Object.assign({}, user, { isDisconnecting: false, isConnected: false });
default:
return user;
}
};
app.module.ts
@NgModule({
declarations: [
AppComponent
https://riptutorial.com/ 188
],
imports: [
// angular modules
// ...
• UserComponent:
[Dumb component] We'll just pass the user object from the store using
@Input property and async pipe. This way, the component will receive the user only once it's
available (and the user will be of type IUser and not of type Observable<IUser> !)
• LoginComponent [Smart component] We'll directly inject the Store into this component and
work only on user as an Observable.
user.component.ts
@Component({
selector: 'user',
styles: [
'.table { max-width: 250px; }',
'.truthy { color: green; font-weight: bold; }',
'.falsy { color: red; }'
],
template: `
<h2>User information :</h2>
<table class="table">
<tr>
<th>Property</th>
<th>Value</th>
</tr>
<tr>
<td>username</td>
<td [class.truthy]="user.username" [class.falsy]="!user.username">
{{ user.username ? user.username : 'null' }}
</td>
</tr>
https://riptutorial.com/ 189
<tr>
<td>email</td>
<td [class.truthy]="user.email" [class.falsy]="!user.email">
{{ user.email ? user.email : 'null' }}
</td>
</tr>
<tr>
<td>isConnecting</td>
<td [class.truthy]="user.isConnecting" [class.falsy]="!user.isConnecting">
{{ user.isConnecting }}
</td>
</tr>
<tr>
<td>isConnected</td>
<td [class.truthy]="user.isConnected" [class.falsy]="!user.isConnected">
{{ user.isConnected }}
</td>
</tr>
<tr>
<td>isDisconnecting</td>
<td [class.truthy]="user.isDisconnecting" [class.falsy]="!user.isDisconnecting">
{{ user.isDisconnecting }}
</td>
</tr>
</table>
`
})
export class UserComponent {
@Input() user;
constructor() { }
}
login.component.ts
@Component({
selector: 'login',
template: `
<form
*ngIf="!(user | async).isConnected"
#loginForm="ngForm"
(ngSubmit)="login(loginForm.value.username)"
>
<input
type="text"
name="username"
placeholder="Username"
[disabled]="(user | async).isConnecting"
ngModel
>
<button
type="submit"
[disabled]="(user | async).isConnecting || (user | async).isConnected"
>Log me in</button>
</form>
https://riptutorial.com/ 190
<button
*ngIf="(user | async).isConnected"
(click)="logout()"
[disabled]="(user | async).isDisconnecting"
>Log me out</button>
`
})
export class LoginComponent {
public user: Observable<IUser>;
login(username: string) {
this.userService.login(username);
}
logout() {
this.userService.logout();
}
}
As Ngrx is a merge of Redux and RxJs concepts, it can be quite hard to understand the ins an outs at
the beginning. But this is a powerful pattern that allows you as we've seen in this example to have
a reactive app and were you can easily share your data. Don't forget that there's a Plunkr available
and you can fork it to make your own tests !
I hope it was helpful even tho the topic is quite long, cheers !
https://riptutorial.com/ 191
Chapter 55: Optimizing rendering using
ChangeDetectionStrategy
Examples
Default vs OnPush
Consider the following component with one input myInput and an internal value called
someInternalValue. Both of them are used in a component's template.
@Component({
template:`
<div>
<p>{{myInput}}</p>
<p>{{someInternalValue}}</p>
</div>
`
})
class MyComponent {
@Input() myInput: any;
someInternalValue: any;
// ...
}
Suppose, however, that we only want to re-render when the inputs change. Consider the following
component with changeDetection: set to ChangeDetectionStrategy.OnPush
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
template:`
<div>
<p>{{myInput}}</p>
<p>{{someInternalValue}}</p>
</div>
`
})
class MyComponent {
@Input() myInput: any;
someInternalValue: any;
https://riptutorial.com/ 192
// ...
}
https://riptutorial.com/ 193
Chapter 56: OrderBy Pipe
Introduction
How to write order pipe and use it.
Examples
The Pipe
@Pipe({
name: 'orderBy',
pure: false
})
export class OrderBy implements PipeTransform {
value:string[] =[];
//Basic array
if(!propertyToCheck || propertyToCheck === '-' || propertyToCheck === '+'){
https://riptutorial.com/ 194
return !desc ? value.sort() : value.sort().reverse();
}else {
let property:string = propertyToCheck.substr(0, 1) === '+' ||
propertyToCheck.substr(0, 1) === '-'
? propertyToCheck.substr(1)
: propertyToCheck;
return value.sort(function(a:any,b:any){
return !desc
? OrderBy._orderByComparator(a[property], b[property])
: -OrderBy._orderByComparator(a[property], b[property]);
});
}
} else {
//Loop over property of the array in order and sort
return value.sort(function(a:any,b:any){
for(let i:number = 0; i < config.length; i++){
let desc = config[i].substr(0, 1) === '-';
let property = config[i].substr(0, 1) === '+' || config[i].substr(0, 1) === '-'
? config[i].substr(1)
: config[i];
How to use the pipe in the HTML - order ascending by first name
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of users | orderBy : ['firstName']>
<td>{{user.firstName}}</td>
<td>{{user.lastName}}</td>
<td>{{user.age}}</td>
</tr>
</tbody>
</table>
How to use the pipe in the HTML - order descending by first name
https://riptutorial.com/ 195
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of users | orderBy : ['-firstName']>
<td>{{user.firstName}}</td>
<td>{{user.lastName}}</td>
<td>{{user.age}}</td>
</tr>
</tbody>
</table>
https://riptutorial.com/ 196
Chapter 57: Page title
Introduction
How can you change the title of the page
Syntax
• setTitle(newTitle: string): void;
• getTitle(): string;
Examples
changing the page title
https://riptutorial.com/ 197
Chapter 58: Pipes
Introduction
The pipe | character is used to apply pipes in Angular 2. Pipes are very similar to filters in
AngularJS in that they both help to transform the data into a specified format.
Parameters
Function/Parameter Explanation
@Pipe({name, pure}) metadata for pipe, must immediately precede pipe class
transform( value,
the function that is called to transform the values in the template
args[]? )
the arguments that you may need included in your transform. Mark
args: any[] optional args with the ? operator like so transform(value, arg1,
arg2?)
Remarks
This topic covers Angular2 Pipes, a mechanism for transforming and formatting data within HTML
templates in an Angular2 application.
Examples
Chaining Pipes
Custom Pipes
my.pipe.ts
https://riptutorial.com/ 198
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'myPipe'})
export class MyPipe implements PipeTransform {
my.component.ts
@Component({
selector: 'my-component',
template: `{{ value | myPipe }}`
})
export class MyComponent {
public value:any;
my.module.ts
@NgModule({
imports: [
BrowserModule,
],
declarations: [
MyComponent,
MyPipe
],
})
export class MyModule { }
Built-in Pipes
https://riptutorial.com/ 199
Pipe Usage Example
Example
hotel-reservation.component.ts
@Component({
moduleId: module.id,
selector: 'hotel-reservation',
templateUrl: './hotel-reservation.template.html'
})
export class HotelReservationComponent {
public fName: string = 'Joe';
public lName: string = 'SCHMO';
public reservationMade: string = '2016-06-22T07:18-08:00'
public reservationFor: string = '2025-11-14';
public cost: number = 99.99;
}
hotel-reservation.template.html
<div>
<h1>Welcome back {{fName | uppercase}} {{lName | lowercase}}</h1>
<p>
On {reservationMade | date} at {reservationMade | date:'shortTime'} you
reserved room 205 for {reservationDate | date} for a total cost of
{cost | currency}.
</p>
</div>
Output
The JsonPipe can be used for debugging the state of any given internal.
Code
https://riptutorial.com/ 200
@Component({
selector: 'json-example',
template: `<div>
<p>Without JSON pipe:</p>
<pre>{{object}}</pre>
<p>With JSON pipe:</p>
<pre>{{object | json}}</pre>
</div>`
})
export class JsonPipeExample {
object: Object = {foo: 'bar', baz: 'qux', nested: {xyz: 3, numbers: [1, 2, 3, 4, 5]}};
}
Output
To make a custom pipe available application wide, During application bootstrap, extending
PLATFORM_PIPES.
bootstrap(AppComponent, [
provide(PLATFORM_PIPES, {
useValue: [
MyPipe
],
multi: true
})
]);
app/pipes.pipe.ts
@Pipe({name: 'truthy'})
export class Truthy implements PipeTransform {
transform(value: any, truthy: string, falsey: string): any {
if (typeof value === 'boolean'){return value ? truthy : falsey;}
else return value
}
https://riptutorial.com/ 201
}
app/my-component.component.ts
@Component({
selector: 'my-component',
template: `
<p>{{value | truthy:'enabled':'disabled' }}</p>
`,
pipes: [Truthy]
})
export class MyComponent{ }
@Component({
selector: 'async-stuff',
template: `
<h1>Hello, {{ name | async }}</h1>
Your Friends are:
<ul>
<li *ngFor="let friend of friends | async">
{{friend}}
</li>
</ul>
`
})
class AsyncStuffComponent {
name = Promise.resolve('Misko');
friends = Observable.of(['Igor']);
}
Becomes:
<h1>Hello, Misko</h1>
Your Friends are:
<ul>
<li>
Igor
</li>
</ul>
@Pipe({name: 'ifDate'})
https://riptutorial.com/ 202
export class IfDate implements PipeTransform {
private datePipe: DatePipe = new DatePipe();
Stateful Pipes
Angular 2 offers two different types of pipes - stateless and stateful. Pipes are stateless by default.
However, we can implement stateful pipes by setting the pure property to false. As you can see in
the parameter section, you can specify a name and declare whether the pipe should be pure or not,
meaning stateful or stateless. While data flows through a stateless pipe (which is a pure function)
that does not remember anything, data can be managed and remembered by stateful pipes. A
good example of a stateful pipe is the AsyncPipe that is provided by Angular 2.
Important
Notice that most pipes should fall into the category of stateless pipes. That's important for
performance reasons since Angular can optimize stateless pipes for the change detector. So use
stateful pipes cautiously. In general, the optimization of pipes in Angular 2 have a major
performance enhancement over filters in Angular 1.x. In Angular 1 the digest cycle always had to
re-run all filters even though the data hasn't changed at all. In Angular 2, once a pipe's value has
been computed, the change detector knows not to run this pipe again unless the input changes.
@Pipe({
name: 'countdown',
pure: false
})
export class CountdownPipe implements PipeTransform, OnDestroy {
private interval: any;
private remainingTime: number;
if (!this.interval) {
this.interval = setInterval(() => {
this.remainingTime--;
https://riptutorial.com/ 203
if (this.remainingTime <= 0) {
this.remainingTime = 0;
clearInterval(this.interval);
delete this.interval;
}
}, interval);
}
return this.remainingTime;
}
ngOnDestroy(): void {
if (this.interval) {
clearInterval(this.interval);
}
}
}
{{ 1000 | countdown:50 }}
{{ 300 | countdown }}
It's important that your pipe also implements the OnDestroy interface so you can clean up once your
pipe gets destroyed. In the example above, it's necessary to clear the interval to avoid memory
leaks.
Dynamic Pipe
Use case scenario: A table view consists of different columns with different data format that needs
to be transformed with different pipes.
table.component.ts
...
import { DYNAMIC_PIPES } from '../pipes/dynamic.pipe.ts';
@Component({
...
pipes: [DYNAMIC_PIPES]
})
export class TableComponent {
...
https://riptutorial.com/ 204
}
dynamic.pipe.ts
import {
Pipe,
PipeTransform
} from '@angular/core';
// Library used to humanize a date in this example
import * as moment from 'moment';
@Pipe({name: 'dynamic'})
export class DynamicPipe implements PipeTransform {
transform(value:string, modifier:string) {
if (!modifier) return value;
// Evaluate pipe string
return eval('this.' + modifier + '(\'' + value + '\')')
}
// Returns a human friendly time format e.g: '14 minutes ago', 'yesterday'
humanizeDate(value:string):string {
// Humanize if date difference is within a week from now else returns 'December 20,
2016' format
if (moment().diff(moment(value), 'days') < 8) return moment(value).fromNow();
return moment(value).format('MMMM Do YYYY');
}
}
table.component.html
<table>
<thead>
<td *ngFor="let head of data.header">{{ head }}</td>
</thead>
<tr *ngFor="let row of table.rows; let i = index">
<td *ngFor="let column of row">{{ column | dynamic:table.pipes[i] }}</td>
</tr>
</table>
Result
https://riptutorial.com/ 205
| 1 | Home | home | 4 minutes ago | Enabled |
| 2 | About Us | about | Yesterday | Enabled |
| 4 | Contact Us | contact | Yesterday | Disabled |
---------------------------------------------------------------------
Testing a pipe
describe('ReversePipe', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ReversePipe],
});
});
https://riptutorial.com/ 206
Chapter 59: Routing
Examples
Basic Routing
Router enables navigation from one view to another based on user interactions with the
application.
<base href='/'>
as the first child under your head tag in your index.html file. This tag tells that your app folder is the
application root. Angular 2 would then know to organize your links.
First step is to check if you are pointing to correct/latest routing dependencies in package.json -
"dependencies": {
......
"@angular/router": "3.0.0-beta.1",
......
}
class Route {
path : string
pathMatch : 'full'|'prefix'
component : Type|string
.........
}
In a routes file (route/routes.ts), import all the components which you need to configure for
different routing paths. Empty path means that view is loaded by default. ":" in the path indicates
dynamic parameter passed to the loaded component.
Routes are made available to application via dependency injection. ProviderRouter method is
called with RouterConfig as parameter so that it can be injected to the components for calling
routing specific tasks.
https://riptutorial.com/ 207
export const appRoutes: RouterConfig = [
{ path: '', pathMatch: 'full', redirectTo: 'login' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'bars/:id', component: BarDetailComponent },
{ path: 'login', component: LoginComponent },
{ path: 'signup', component: SignupComponent }
];
In your main.ts (It can be any name. basically, it should your main file defined in systemjs.config)
Fourth step is to load/display the router components based on path accessed. directive is used to
tell angular where to load the component. To use import the ROUTER_DIRECTIVES.
@Component({
selector: 'demo-app',
template: `
....................................
<div>
<router-outlet></router-outlet>
</div>
....................................
`,
// Add our router directives we will be using
directives: [ROUTER_DIRECTIVES]
})
Fifth step is to link the other routes. By default, RouterOutlet will load the component for which
empty path is specified in the RouterConfig. RouterLink directive is used with html anchor tag to
load the components attached to routes. RouterLink generates the href attribute which is used to
generate links. For Ex:
@Component({
selector: 'demo-app',
template: `
<a [routerLink]="['/login']">Login</a>
<a [routerLink]="['/signup']">Signup</a>
<a [routerLink]="['/dashboard']">Dashboard</a>
<div>
<router-outlet></router-outlet>
</div>
`,
https://riptutorial.com/ 208
// Add our router directives we will be using
directives: [ROUTER_DIRECTIVES]
})
export class AppComponent { }
Now, we are good with routing to static path. RouterLink support dynamic path also by passing
extra parameters along with the path.
@Component({
selector: 'demo-app',
template: `
<ul>
<li *ngFor="let bar of bars | async">
<a [routerLink]="['/bars', bar.id]">
{{bar.name}}
</a>
</li>
</ul>
<div>
<router-outlet></router-outlet>
</div>
`,
// Add our router directives we will be using
directives: [ROUTER_DIRECTIVES]
})
export class AppComponent { }
RouterLink takes an array where first element is the path for routing and subsequent elements are
for the dynamic routing parameters.
Child Routes
Sometimes it makes sense to nest view's or routes within one another. For example on the
dashboard you want several sub views, similar to tabs but implemented via the routing system, to
show the users' projects, contacts, messages ets. In order to support such scenarios the router
allows us to define child routes.
First we adjust our RouterConfig from above and add the child routes:
https://riptutorial.com/ 209
{ path: 'signup', component: SignupComponent }
];
Now that we have our child routes defined we have to make sure those child routes can be
displayed within our DashboardComponent, since that's where we have added the childs to. Previously
we have learned that the components are displayed in a <router-outlet></router-outlet> tag.
Similar we declare another RouterOutlet in the DashboardComponent:
@Component({
selector: 'dashboard',
template: `
<a [routerLink]="['projects']">Projects</a>
<a [routerLink]="['messages']">Messages</a>
<div>
<router-outlet></router-outlet>
</div>
`
})
export class DashboardComponent { }
As you can see, we have added another RouterOutlet in which the child routes will be displayed.
Usually the route with an empty path will be shown, however, we set up a redirect to the projects
route, because we want that to be shown immediately when the dashboard route is loaded. That
being said, we need an empty route, otherwise you'll get an error like this:
So by adding the empty route, meaning a route with an empty path, we have defined an entry
point for the router.
ResolveData
This example will show you how you can resolve data fetched from a service before rendering
your application's view.
users.service.ts
...
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import { User } from './user.ts';
@Injectable()
export class UsersService {
constructor(public http:Http) {}
https://riptutorial.com/ 210
/**
* Returns all users
* @returns {Observable<User[]>}
*/
index():Observable<User[]> {
return this.http.get('http://mywebsite.com/api/v1/users')
.map((res:Response) => res.json());
}
/**
* Returns a user by ID
* @param id
* @returns {Observable<User>}
*/
get(id:number|string):Observable<User> {
users.resolver.ts
...
import { UsersService } from './users.service.ts';
import { Observable } from 'rxjs/Rx';
import {
Resolve,
ActivatedRouteSnapshot,
RouterStateSnapshot
} from "@angular/router";
@Injectable()
export class UsersResolver implements Resolve<User[] | User> {
users.component.ts
This is a page component with a list of all users. It will work similarly for User detail page
component, replace data.users with data.user or whatever key defined in app.routes.ts(see below)
...
https://riptutorial.com/ 211
import { ActivatedRoute} from "@angular/router";
@Component(...)
export class UsersComponent {
users:User[];
constructor(route: ActivatedRoute) {
route.data.subscribe(data => {
// data['Match key defined in RouterConfig, see below']
this.users = data.users;
});
}
/**
* It is not required to unsubscribe from the resolver as Angular's HTTP
* automatically completes the subscription when data is received from the server
*/
}
app.routes.ts
...
import { UsersResolver } from './resolvers/users.resolver';
app.resolver.ts
IMPORTANT: Services used in resolver must be imported first or you will get a 'No provider for
..Resolver error'. Remember that these services will be available globally and you will not need to
https://riptutorial.com/ 212
declare them in any component's providers anymore. Be sure to unsubscribe from any
subscription to prevent memory leak
...
import { UsersService } from './users.service';
import { UsersResolver } from './users.resolver';
main.browser.ts
...
import {bootstrap} from '@angular/platform-browser-dynamic';
import { ROUTE_RESOLVERS } from './app.resolver';
bootstrap(<Type>App, [
...
...ROUTE_RESOLVERS
])
.catch(err => console.error(err));
Contrary to original documentation, I found this to be the way to properly nest children routes
inside the app.routing.ts or app.module.ts file (depending on your preference). This approach
works when using either WebPack or SystemJS.
The example below shows routes for home, home/counter, and home/counter/fetch-data. The first
and last routes being examples of redirects. Finally at the end of the example is a proper way to
export the Route to be imported in a separate file. For ex. app.module.ts
To further explain, Angular requires that you have a pathless route in the children array that
includes the parent component, to represent the parent route. It's a little confusing but if you think
about a blank URL for a child route, it would essentially equal the same URL as the parent route.
https://riptutorial.com/ 213
{
path: "home",
children: [
{
path: "",
component: HomeComponent
},
{
path: "counter",
children: [
{
path: "",
component: CounterComponent
},
{
path: "fetch-data",
component: FetchDataComponent
}
]
}
]
},
{
path: "**",
redirectTo: "home"
}
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
export class AppRoutingModule { }
https://riptutorial.com/ 214
Chapter 60: Routing (3.0.0+)
Remarks
There are a few more tricks we can do with the router (such as restricting access), but those can
be covered in a separate tutorial.
If you need a new route, simply modify app.routes.ts and follow the following steps:
Examples
Bootstrapping
Now that the routes are defined, we need to let our application know about the routes. To do this,
bootstrap the provider we exported in the previous example.
Find your bootstrap configuration (should be in main.ts, but your mileage may vary).
//main.ts
bootstrap(App, [
APP_ROUTES_PROVIDER,
])
.catch(err => console.error(err));
Configuring router-outlet
Now that the router is configured and our app knows how to handle the routes, we need to show
the actual components that we configured.
To do so, configure your HTML template/file for your top-level (app) component like so:
//app.ts
@Component({
selector: 'app',
https://riptutorial.com/ 215
templateUrl: 'app.html',
styleUrls: ['app.css'],
directives: [
ROUTER_DIRECTIVES,
]
})
export class App {
constructor() {
}
}
The <router-outlet></router-outlet> element will switch the content given the route. Another good
aspect about this element is that it does not have to be the only element in your HTML.
For example: Lets say you wanted a a toolbar on every page that stays constant between routes,
similar to how Stack Overflow looks. You can nest the <router-outlet> under elements so that only
certain parts of the page change.
Now that the routes are set up, we need some way to actually change routes.
This example will show how to change routes using the template, but it is possible to change
routes in TypeScript.
<a routerLink="/home">Home</a>
If the user clicks on that link, it will route to /home. The router knows how to handle /home, so it will
display the Home Component.
Which would require an array called links to exist, so add this to app.ts:
public links[] = [
'home',
'login'
]
This will loop through the array and add an <a> element with the routerLink directive = the value of
the current element in the array, creating this:
https://riptutorial.com/ 216
<a routerLink="home">home</a>
<a routerLink="login">login</a>
This is particularly helpful if you have a lot of links, or maybe the links need to be constantly
changed. We let Angular handle the busy work of adding links by just feeding it the info it requires.
Right now, links[] is static, but it is possible to feed it data from another source.
NOTE: This example is based on the 3.0.0.-beta.2 release of the @angular/router. At the
time of writing, this is the latest version of the router.
To use the router, define routes in a new TypeScript file like such
//app.routes.ts
In the first line, we import provideRouter so we can let our application know what the routes are
during the bootstrap phase.
Homeand Profile are just two components as an example. You will need to import each Component
you need as a route.
path:
The path to the component. YOU DO NOT NEED TO USE '/........' Angular will do this
automatically
redirectTo:Optional. If you need to automatically redirect a user when they access a particular
route, supply this.
Finally, we export the configured router. provideRouter will return a provider that we can boostrap
so our application knows how to handle each route.
The default Angular router allows navigation to and from any route unconditionally. This is not
https://riptutorial.com/ 217
always the desired behavior.
In a scenario where a user may conditionally be allowed to navigate to or from a route, a Route
Guard may be used to restrict this behavior.
If your scenario fits one of the following, consider using a Route Guard,
These interfaces can be implemented in your guard to grant or remove access to certain
processes of the navigation.
A synchronous route guard returns a boolean, such as by computing an immediate result, in order
https://riptutorial.com/ 218
to conditionally control navigation.
@Injectable()
export class SynchronousGuard implements CanActivate {
canActivate() {
console.log('SynchronousGuard#canActivate called');
return true;
}
}
For more complex behavior, a route guard can asynchronously block navigation. An asynchronous
route guard can return an Observable or Promise.
This is useful for situations like waiting for user input to answer a question, waiting to successfully
save changes to the server, or waiting to receive data fetched from a remote server.
@Injectable()
export class AsynchronousGuard implements CanActivate {
constructor(private router: Router, private auth: MockAuthenticationService) {}
canActivate(route:ActivatedRouteSnapshot,
state:RouterStateSnapshot):Observable<boolean>|boolean {
this.auth.subscribe((authenticated) => {
if (authenticated) {
return true;
}
this.router.navigateByUrl('/login');
return false;
});
}
}
File app.routes
//components
import { LoginComponent } from './login/login.component';
https://riptutorial.com/ 219
import { DashboardComponent } from './dashboard/dashboard.component';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS
])
.then(success => console.log(`Bootstrap success`))
.catch(error => console.log(error));
We're using a toplevel guard in our route config to catch the current user on first page load, and a
resolver to store the value of the currentUser, which is our authenticated user from the backend.
https://riptutorial.com/ 220
currentUser: CurrentUserResolver
},
children: [...[
path: '',
component: ProfileCmp,
resolve: {
currentUser: currentUser
}
]]
}
];
@Injectable()
export class AuthService {
constructor(http: Http) {
this.http = http;
@Injectable()
export class AuthGuard implements CanActivate {
constructor(auth: AuthService) {
this.auth = auth;
}
canActivate(route, state) {
return Observable
.merge(this.auth.fetchCurrentUser(), Observable.of(true))
.filter(x => x == true);
}
}
https://riptutorial.com/ 221
import { Resolve } from "@angular/router";
import { Observable } from 'rxjs/Rx';
@Injectable()
export class CurrentUserResolver implements Resolve {
constructor(auth: AuthService) {
this.auth = auth;
}
resolve(route, state) {
return this.auth.currentUser;
}
}
https://riptutorial.com/ 222
Chapter 61: Service Worker
Introduction
We will see how to set up a service working on angular, to allow our web app to have offline
capabilities.
A Service worker is a special script which runs in the background in the browser and manages
network requests to a given origin. It's originally installed by an app and stays resident on the
user's machine/device. It's activated by the browser when a page from its origin is loaded and has
the option to respond to HTTP requests during the page loading
Examples
Add Service Worker to our app
First in case you are consulting mobile.angular.io the flag --mobile doesn't work anymore.
ng new serviceWorking-example
cd serviceWorking-example
Now the important thing, to said to angular cli that we want to use service worker we need to do:
ng set apps.0.serviceWorker=true
If for some reason you don’t have @angular/service-worker installed, you will see a message:
Check the .angular-cli.json and you now should see this: "serviceWorker": true
When this flag is true, production builds will be set up with a service worker.
A ngsw-manifest.json file will be generated (or augmented in case we have create a ngsw-
manifest.json in the root of the project, usually this is done to specify the routing ,in a future this
will probably be done automatic) in the dist/ root, and the service worker script will be copied there.
A short script will be added to index.html to register the service worker.
https://riptutorial.com/ 223
• worker-basic.min.js
• sw-register.HASH.bundle.js
• ngsw-manifest.json
Also, index.html now includes this sw-register script, which registers a Angular Service Worker
(ASW) for us.
Refresh the page in your browser (served by the Web Server for Chrome)
Now our application, should load faster and we should be able to use the app offline.
Now if you enable the offline mode in the chrome console , you should see that our app in
http://localhost:4200/index.html is working without connection to internet.
But in http://localhost:4200/ we have a problem and it doesn't load, this is due to the static content
cache only serves files listed in the manifest.
For example, if the manifest declares a URL of /index.html, requests to /index.html will be
answered by the cache, but a request to / or /some/route will go to the network.
That's where the route redirection plugin comes in. It reads a routing config from the manifest and
redirects configured routes to a specified index route.
https://riptutorial.com/ 224
So if now we create or ngsw-manifest.json in the root of the project
{
"routing": {
"routes": {
"/": {
"prefix": false
}
},
"index": "/index.html"
}
}
And we build again our app, now when we go to http://localhost:4200/, we should be redirected to
http://localhost:4200/index.html.
For further information about routing read the official documentation here
https://developers.google.com/web/fundamentals/getting-started/primers/service-workers
https://docs.google.com/document/d/19S5ozevWighny788nI99worpcIMDnwWVmaJDGf_RoDY/edit#
And here you can see an alternative way to implement the service working using SW precache
library :
https://coryrylan.com/blog/fast-offline-angular-apps-with-service-workers
https://riptutorial.com/ 225
Chapter 62: Services and Dependency
Injection
Examples
Example service
services/my.service.ts
@Injectable()
export class MyService {
data: any = [1, 2, 3];
getData() {
return this.data;
}
}
The service provider registration in the bootstrap method will make the service available globally.
main.ts
bootstrap(AppComponent, [MyService]);
In version RC5 global service provider registration can be done inside the module file. In order to
get a single instance of your service for your whole application the service should be declared in
the providers list in the ngmodule of your application. app_module.ts
@NgModule({
declarations: [ AppComponent ],
imports: [ BrowserModule,
routing,
RouterModule,
HttpModule ],
providers: [ appRoutingProviders,
https://riptutorial.com/ 226
MyService
],
bootstrap: [AppComponent],
})
export class AppModule {}
Usage in MyComponent
components/my.component.ts
@Component({
...
...
providers:[MyService] //
})
export class MyComponent implements OnInit {
data: any[];
// Creates private variable myService to use, of type MyService
constructor(private myService: MyService) { }
ngOnInit() {
this.data = this.myService.getData();
}
}
services/my.service.ts
@Injectable()
export class MyService {
data: any = [1, 2, 3];
getData() {
return Promise.resolve(this.data);
}
}
getData() now acts likes a REST call that creates a Promise, which gets resolved immediately.
The results can be handheld inside .then() and errors can also be detected. This is good practice
and convention for asynchronous methods.
components/my.component.ts
https://riptutorial.com/ 227
import { MyService } from '../services/my.service';
@Component({...})
export class MyComponent implements OnInit {
data: any[];
// Creates private variable myService to use, of type MyService
constructor(private myService: MyService) { }
ngOnInit() {
// Uses an "arrow" function to set data
this.myService.getData().then(data => this.data = data);
}
}
Testing a Service
import 'rxjs/add/operator/toPromise';
interface LoginCredentials {
password: string;
user: string;
}
@Injectable()
export class AuthService {
constructor(private http: Http) { }
return response.json();
}
}
describe('AuthService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
AuthService,
https://riptutorial.com/ 228
Http,
{ provide: ConnectionBackend, useClass: MockBackend },
]
});
});
// Alternative 1
it('should login user if right credentials are passed', async(
inject([AuthService], async (authService) => {
const backend: MockBackend = TestBed.get(ConnectionBackend);
const http: Http = TestBed.get(Http);
expect(result).toEqual({
accessToken: 'abcdef',
});
}))
);
// Alternative 2
it('should login user if right credentials are passed', async () => {
const backend: MockBackend = TestBed.get(ConnectionBackend);
const http: Http = TestBed.get(Http);
expect(result).toEqual({
accessToken: 'abcdef',
});
});
https://riptutorial.com/ 229
// Alternative 3
it('should login user if right credentials are passed', async (done) => {
const authService: AuthService = TestBed.get(AuthService);
try {
const result = await authService.signIn({ password: 'ok', user: 'bruno' });
expect(result).toEqual({
accessToken: 'abcdef',
});
done();
} catch (err) {
fail(err);
done();
}
});
});
https://riptutorial.com/ 230
Chapter 63: Templates
Introduction
Templates are very similar to templates in Angular 1, though there are many small syntactical
changes that make it more clear what is happening.
Examples
Angular 2 Templates
A SIMPLE TEMPLATE
Let’s start with a very simple template that shows our name and our favorite thing:
<div>
Hello my name is {{name}} and I like {{thing}} quite a lot.
</div>
{}: RENDERING
My name is {{name}}
Pipes, previously known as “Filters,” transform a value into a new value, like localizing a string or
converting a floating point value into a currency representation:
To resolve and bind a variable to a component, use the [] syntax. If we have this.currentVolume in
our component, we will pass this through to our component and the values will stay in sync:
<video-control [volume]="currentVolume"></video-control>
(): HANDLING EVENTS
(): HANDLING EVENTS To listen for an event on a component, we use the () syntax
<my-component (click)="onClick($event)"></my-component>
To keep a binding up to date given user input and other events, use the [()] syntax. Think of it as a
combination of handling an event and binding a property:
<input [(ngModel)]="myName"> The this.myName value of your component will stay in sync with
https://riptutorial.com/ 231
the input value.
*: THE ASTERISK
Indicates that this directive treats this component as a template and will not draw it as-is. For
example, ngFor takes our and stamps it out for each item in items, but it never renders our initial
since it’s a template:
Other similar directives that work on templates rather than rendered components are *ngIf and
*ngSwitch.
https://riptutorial.com/ 232
Chapter 64: Testing an Angular 2 App
Examples
Installing the Jasmine testing framework
The most common way to test Angular 2 apps is with the Jasmine test framework. Jasmine allows
you to test your code in the browser.
Install
To get started, all you need is the jasmine-core package (not jasmine).
Verify
To verify that Jasmine is set up properly, create the file ./src/unit-tests.html with the following
content and open it in the browser.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>Ng App Unit Tests</title>
<link rel="stylesheet" href="../node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
<script src="../node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
<script src="../node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
<script src="../node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
</head>
<body>
<!-- Unit Testing Chapter #1: Proof of life. -->
<script>
it('true is true', function () {
expect(true).toEqual(true);
});
</script>
</body>
</html>
The first thing we need is to tell karma to use Webpack to read our tests, under a configuration we
set for the webpack engine. Here, I am using babel because I write my code in ES6, you can
change that for other flavors, such as Typescript. Or I use Pug (formerly Jade) templates, you
don't have to.
https://riptutorial.com/ 233
Still, the strategy remains the same.
preprocessors: {
"./karma.shim.js":["webpack"]
},
webpack: packConfig,
https://riptutorial.com/ 234
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
browsers: ['PhantomJS'],
concurrency: Infinity,
autoWatch: false,
singleRun: true
});
};
So far, we have told Karma to use webpack, and we have told it to start at a file called
karma.shim.js. this file will have the job of acting as the starting point for webpack. webpack will
read this file and use the import and require statements to gather all our dependencies and run
our tests.
import "zone.js/dist/zone";
import "zone.js/dist/long-stack-trace-zone";
import "zone.js/dist/jasmine-patch";
import "zone.js/dist/async-test";
import "zone.js/dist/fake-async-test";
import "zone.js/dist/sync-test";
import "zone.js/dist/proxy-zone";
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';
Error.stackTraceLimit = Infinity;
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting());
In essence, we are importing TestBed from angular core testing, and initiating the environment, as
it needs to be initiated only once for all of our tests. Then, we are going through the src/app
directory recursively and reading every file that ends with .spec.js and feed them to testContext,
so they will run.
https://riptutorial.com/ 235
I usually try to put my tests the same place as the class. Personat taste, it makes it easier for me
to import dependencies and refactor tests with classes. But if you want to put your tests
somewhere else, like under src/test directory for example, here is you chance. change the line
before last in the karma.shim.js file.
Perfect. what is left? ah, the gulp task that uses the karma.config.js file we made above:
gulp.task("karmaTests",function(done){
var Server = require("karma").Server;
new Server({
configFile : "./karma.config.js",
singleRun: true,
autoWatch: false
}, function(result){
return result ? done(new Error(`Karma failed with error code ${result}`)):done();
}).start();
});
I am now starting the server with the config file we created, telling it to run once and don't watch
for changes. I find this to suite me better as the tests will run only if I am ready for them to run, but
of course if you want different you know where to change.
And as my final code sample, here is a set of tests for the Angular 2 tutorial, "Tour of Heroes".
import {
TestBed,
ComponentFixture,
async
} from "@angular/core/testing";
beforeEach(()=> {
TestBed.configureTestingModule({
imports: [AppModule]
});
this.fixture = TestBed.createComponent(AppComponent);
this.fixture.detectChanges();
});
https://riptutorial.com/ 236
it("Should have an array of heros", async(()=>
this.fixture.whenStable().then(()=> {
const cmp = this.fixture.componentInstance;
expect(cmp.heroes).toBeDefined("component should have a list of heroes");
expect(cmp.heroes.length).toEqual(10, "heroes list should have 10 members");
cmp.heroes.map((h, i)=> {
expect(h instanceof Hero).toBeTruthy(`member ${i} is not a Hero instance.
${h}`)
});
})));
spyOn(cmp,"onSelect").and.callThrough();
this.fixture.nativeElement.querySelectorAll("ul.heroes li")[5].click();
expect(cmp.onSelect)
.toHaveBeenCalledWith(cmp.heroes[5]);
expect(cmp.selectedHero)
.toEqual(cmp.heroes[5], "click on hero should change hero");
})
));
});
Noteworthy in this is how we have beforeEach() configure a test module and create the
https://riptutorial.com/ 237
component in test, and how we call detectChanges() so that angular actually goes through the
double-binding and all.
Notice that each test is a call to async() and it always waits for whenStable promise to resolve
before examining the fixture. It then has access to the component through componentInstance
and to the element through nativeElement.
There is one test which is checking the correct styling. as part of the Tutorial, Angular team
demonstrates use of styles inside components. In our test, we use getComputedStyle() to check
that styles are coming from where we specified, however we need the Window object for that, and
we are getting it from the element as you can see in the test.
Usually, services call remote Api to retrieve/send data. But unit tests shouldn't do network calls.
Angular internally uses XHRBackend class to do http requests. User can override this to change
behavior. Angular testing module provides MockBackend and MockConnection classes which can be
used to test and assert http requests.
import 'rxjs/add/operator/map';
@Injectable()
export class PostsService {
posts: IPost[];
get(): Observable<IPost[]> {
return this.http.get(this.postsUri)
.map((response) => response.json());
}
}
posts.service.spec.ts Here, we will test above service by mocking http api calls.
https://riptutorial.com/ 238
XHRBackend,
ResponseOptions,
Response,
RequestMethod
} from '@angular/http';
import {
MockBackend,
MockConnection
} from '@angular/http/testing';
describe('PostsService', () => {
// Mock http response
const mockResponse = [
{
'userId': 1,
'id': 1,
'title': 'sunt aut facere repellat provident occaecati excepturi optio
reprehenderit',
'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et
cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet
architecto'
},
{
'userId': 1,
'id': 2,
'title': 'qui est esse',
'body': 'est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea
dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui
aperiam non debitis possimus qui neque nisi nulla'
},
{
'userId': 1,
'id': 3,
'title': 'ea molestias quasi exercitationem repellat qui ipsa sit aut',
'body': 'et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut
ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et
velit aut'
},
{
'userId': 1,
'id': 4,
'title': 'eum et est occaecati',
'body': 'ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda
provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt
voluptatem rerum illo velit'
}
];
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
{
provide: XHRBackend,
// This provides mocked XHR backend
useClass: MockBackend
},
PostsService
]
https://riptutorial.com/ 239
});
});
expect(connection.request.url).toBe('http://jsonplaceholder.typicode.com/posts');
// Send mock response
connection.mockRespond(new Response(new ResponseOptions({
body: mockResponse
})));
});
postsService.get()
.subscribe((posts) => {
expect(posts).toBe(mockResponse);
});
})));
});
@Component({
selector: 'my-app',
template: '<h1>{{title}}</h1>'
})
export class MyAppComponent{
title = 'welcome';
}
For angular testing, angular provide its testing utilities along with the testing framework which
helps in writing the good test case in angular. Angular utilities can be imported from
@angular/core/testing
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
MyAppComponent
]
https://riptutorial.com/ 240
});
});
beforeEach(() => {
fixture = TestBed.createComponent(MyAppComponent);
comp = fixture.componentInstance;
});
expect(comp).toBeTruthy();
});
});
In the above example, there is only one test case which explain the test case for component
existence. In the above example angular testing utilities like TestBed and ComponentFixture are
used.
TestBed is used to create the angular testing module and we configure this module with the
configureTestingModule method to produce the module environment for the class we want to test.
Testing module to be configured before the execution of every test case that's why we configure
the testing module in the beforeEach function.
createComponent method of TestBed is used to create the instance of the component under test.
createComponent return the ComponentFixture. The fixture provides access to the component instance
itself.
https://riptutorial.com/ 241
Chapter 65: Testing ngModel
Introduction
Is a example for how you can test a component in Angular2 that have a ngModel.
Examples
Basic test
describe('MyComponent:',()=> {
const template = `
<div>
<my-component type="text" [(ngModel)]="value" name="TestName" size="9" min="3" max="8"
placeholder="testPlaceholder" disabled=false required=false></my-component>
</div>
`;
let fixture:any;
let element:any;
let context:any;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [InlineEditorComponent],
imports: [
FormsModule,
InlineEditorModule]
});
fixture = TestBed.overrideComponent(InlineEditorComponent, {
set: {
selector:"inline-editor-test",
template: template
}})
.createComponent(InlineEditorComponent);
context = fixture.componentInstance;
fixture.detectChanges();
});
https://riptutorial.com/ 242
let input = fixture.nativeElement.querySelector("input");
input.value = "Username";
dispatchEvent(input, 'input');
fixture.detectChanges();
fixture.whenStable().then(() => {
//this button dispatch event for save the text in component.value
fixture.nativeElement.querySelectorAll('button')[0].click();
expect(context.value).toBe("Username");
});
});
});
https://riptutorial.com/ 243
Chapter 66: unit testing
Examples
Basic unit test
component file
@Component({
selector: 'example-test-compnent',
template: '<div>
<div>{{user.name}}</div>
<div>{{user.fname}}</div>
<div>{{user.email}}</div>
</div>'
})
Test file
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ExampleTestComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ExampleTestComponent );
component = fixture.componentInstance;
fixture.detectChanges();
});
expect(component.user.name).toEqual('name');
expect(component.user.fname).toEqual('fname');
https://riptutorial.com/ 244
expect(component.user.email).toEqual('email');
});
});
https://riptutorial.com/ 245
Chapter 67: Update typings
Examples
Update typings when: typings WARN deprecated
Warning message:
https://riptutorial.com/ 246
Chapter 68: Use native webcomponents in
Angular 2
Remarks
When you use a web component in your Angular 2 template, angular will try to find a component
with a selector matching the custom tag of the web component - which it of course can't and will
throw an error.
The solution is to import a "custom elements schema" in the module that holds the component.
This will make angular accept any custom tag, that doesn't match any ng component selector.
Examples
Include custom elements schema in your module
@NgModule({
imports: [ CommonModule ],
declarations: [ AboutComponent ],
exports: [ AboutComponent ],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
@Component({
selector: 'myapp-about',
template: `<my-webcomponent></my-webcomponent>`
})
export class AboutComponent { }
https://riptutorial.com/ 247
Chapter 69: Using third party libraries like
jQuery in Angular 2
Introduction
When building applications using Angular 2.x there are times when it's required to use any third
party libraries like jQuery, Google Analytics, Chat Integration JavaScript APIs and etc.
Examples
Configuration using angular-cli
NPM
If external library like jQuery is installed using NPM
"scripts": [
"../node_modules/jquery/dist/jquery.js"
]
Assets Folder
You can also save the library file in your assets/js directory and include the same in angular-
cli.json
"scripts": [
"assets/js/jquery.js"
]
Note
Save your main library jquery and their dependencies like jquery-cycle-plugin into the assets
directory and add both of them into angular-cli.json, make sure the order is maintained for the
dependencies.
To use jquery in your Angular 2.x components, declare a global variable on the top
https://riptutorial.com/ 248
declare var $: any;
This will allow using $ or jQuery into your Angular 2.x component.
https://riptutorial.com/ 249
Chapter 70: Zone.js
Examples
Getting reference to NgZone
my.component.ts
@Component({...})
export class Mycomponent implements NgOnInit {
constructor(private _ngZone: NgZone) { }
ngOnInit() {
this._ngZone.runOutsideAngular(() => {
// Do something outside Angular so it won't get noticed
});
}
}
runOutsideAngularcan be used to run code outside Angular 2 so that it does not trigger change
detection unnecessarily. This can be used to for example run multiple HTTP request to get all the
data before rendering it. To execute code again inside Angular 2, run method of NgZone can be
used.
my.component.ts
@Component({...})
export class Mycomponent implements OnInit {
private data: any[];
constructor(private http: Http, private _ngZone: NgZone) { }
ngOnInit() {
this._ngZone.runOutsideAngular(() => {
this.http.get('resource1').subscribe((data1:any) => {
// First response came back, so its data can be used in consecutive request
this.http.get(`resource2?id=${data1['id']}`).subscribe((data2:any) => {
this.http.get(`resource3?id1=${data1['id']}&id2=${data2}`).subscribe((data3:any) =>
{
this._ngZone.run(() => {
this.data = [data1, data2, data3];
});
});
});
});
});
https://riptutorial.com/ 250
}
}
https://riptutorial.com/ 251
Credits
S.
Chapters Contributors
No
Angular RXJS Subjects and daniellmb, Maciej Treder, Ronald Zarīts, Sam
11
Observables with API requests Storie, Sébastien Temprado, willydee
https://riptutorial.com/ 252
14 Angular2 Custom Validations Arnold Wiersma, Norsk, Yoav Schniederman
24 Barrel TechJhola
30 Components BrunoLM
https://riptutorial.com/ 253
custom ngx-bootstrap datepicker +
35 Yoav Schniederman
input
Installing 3rd party plugins with Alex Morales, Daredzik, filoxo, Kaspars Bergs,
48
[email protected] pd farhad
52 Modules BrunoLM
53 ngrx Maxime
https://riptutorial.com/ 254
Optimizing rendering using
54 daniellmb, Eric Jimenez, Everettss
ChangeDetectionStrategy
https://riptutorial.com/ 255