docs: split intro into separate chapters, shuffle code, update to alph52
closes #483 A major refactoring of the intro chapters includes text revision and the addition of "module" as an 8th "basic building block". Incorporates John Papa feedback.
|
@ -0,0 +1,13 @@
|
||||||
|
// #docregion import
|
||||||
|
import {Component} from 'angular2/core';
|
||||||
|
// #enddocregion import
|
||||||
|
import {HeroListComponent} from './hero-list.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-app',
|
||||||
|
template: '<hero-list></hero-list>',
|
||||||
|
directives: [HeroListComponent]
|
||||||
|
})
|
||||||
|
// #docregion export
|
||||||
|
export class AppComponent { }
|
||||||
|
// #enddocregion export
|
|
@ -1,17 +1,17 @@
|
||||||
import {Injectable} from 'angular2/angular2';
|
import {Injectable} from 'angular2/core';
|
||||||
import {Logger} from './logger.service';
|
import {Logger} from './logger.service';
|
||||||
import {Hero} from './hero';
|
import {Hero} from './hero';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BackendService {
|
export class BackendService {
|
||||||
constructor(private _logger: Logger) {}
|
constructor(private _logger: Logger) {}
|
||||||
|
|
||||||
getAll<T>(type: {new(...args:any[]): any }) : any[]{
|
getAll<T>(type: {new(...args:any[]): any }) : any[]{
|
||||||
if (type === Hero) {
|
if (type === Hero) {
|
||||||
// TODO get from the database and return as a promise
|
// TODO get from the database and return as a promise
|
||||||
return [
|
return [
|
||||||
new Hero('Windstorm', 'Weather mastery'),
|
new Hero('Windstorm', 'Weather mastery'),
|
||||||
new Hero('Mr. Nice', 'Killing them with kindness'),
|
new Hero('Mr. Nice', 'Killing them with kindness'),
|
||||||
new Hero('Magneta', 'Manipulates metalic objects')];
|
new Hero('Magneta', 'Manipulates metalic objects')];
|
||||||
}
|
}
|
||||||
let err = new Error('Cannot get object of this type');
|
let err = new Error('Cannot get object of this type');
|
|
@ -0,0 +1,13 @@
|
||||||
|
import {bootstrap} from 'angular2/platform/browser';
|
||||||
|
// #docregion import
|
||||||
|
import {AppComponent} from './app.component';
|
||||||
|
// #enddocregion import
|
||||||
|
import {HeroService} from './hero.service';
|
||||||
|
import {BackendService} from './backend.service';
|
||||||
|
import {Logger} from './logger.service';
|
||||||
|
|
||||||
|
// #docregion bootstrap
|
||||||
|
bootstrap(AppComponent, [
|
||||||
|
BackendService, HeroService, Logger
|
||||||
|
]);
|
||||||
|
// #enddocregion bootstrap
|
|
@ -0,0 +1,9 @@
|
||||||
|
<hr>
|
||||||
|
<h4>{{hero.name}} Detail</h4>
|
||||||
|
<div>Id: {{hero.id}}</div>
|
||||||
|
<div>Name:
|
||||||
|
<!-- #docregion ngModel -->
|
||||||
|
<input [(ngModel)]="hero.name">
|
||||||
|
<!-- #enddocregion ngModel -->
|
||||||
|
</div>
|
||||||
|
<div>Power:<input [(ngModel)]="hero.power"></div>
|
|
@ -1,4 +1,4 @@
|
||||||
import {Component, Input} from 'angular2/angular2';
|
import {Component, Input} from 'angular2/core';
|
||||||
import {Hero} from './hero';
|
import {Hero} from './hero';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!--#docregion binding -->
|
||||||
|
<div>{{hero.name}}</div>
|
||||||
|
<hero-detail [hero]="selectedHero"></hero-detail>
|
||||||
|
<div (click)="selectHero(hero)></div>
|
||||||
|
|
||||||
|
<!--#enddocregion binding -->
|
||||||
|
|
||||||
|
<!--#docregion structural -->
|
||||||
|
<div *ngFor="#hero of heroes"></div>
|
||||||
|
<hero-detail *ngIf="selectedHero"></hero-detail>
|
||||||
|
|
||||||
|
<!--#enddocregion structural -->
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!-- #docregion -->
|
||||||
|
<h2>Hero List</h2>
|
||||||
|
|
||||||
|
<p><i>Pick a hero from the list</i></p>
|
||||||
|
<div *ngFor="#hero of heroes" (click)="selectHero(hero)">
|
||||||
|
{{hero.name}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>
|
|
@ -1,6 +1,6 @@
|
||||||
// #docplaster
|
// #docplaster
|
||||||
|
|
||||||
import {Component} from 'angular2/angular2';
|
import {Component} from 'angular2/core';
|
||||||
import {Hero} from './hero';
|
import {Hero} from './hero';
|
||||||
import {HeroDetailComponent} from './hero-detail.component';
|
import {HeroDetailComponent} from './hero-detail.component';
|
||||||
import {HeroService} from './hero.service'
|
import {HeroService} from './hero.service'
|
||||||
|
@ -12,7 +12,7 @@ import {HeroService} from './hero.service'
|
||||||
selector: 'hero-list',
|
selector: 'hero-list',
|
||||||
templateUrl: 'app/hero-list.component.html',
|
templateUrl: 'app/hero-list.component.html',
|
||||||
directives: [HeroDetailComponent],
|
directives: [HeroDetailComponent],
|
||||||
// #docregion providers
|
// #docregion providers
|
||||||
providers: [HeroService]
|
providers: [HeroService]
|
||||||
})
|
})
|
||||||
// #enddocregion providers
|
// #enddocregion providers
|
||||||
|
@ -25,7 +25,7 @@ export class HeroesComponent { ... }
|
||||||
// #docregion class
|
// #docregion class
|
||||||
export class HeroListComponent {
|
export class HeroListComponent {
|
||||||
// #docregion ctor
|
// #docregion ctor
|
||||||
constructor(service: HeroService) {
|
constructor(service: HeroService) {
|
||||||
this.heroes = service.getHeroes();
|
this.heroes = service.getHeroes();
|
||||||
}
|
}
|
||||||
// #enddocregion ctor
|
// #enddocregion ctor
|
|
@ -1,4 +1,4 @@
|
||||||
import {Injectable} from 'angular2/angular2';
|
import {Injectable} from 'angular2/core';
|
||||||
import {Hero} from './hero';
|
import {Hero} from './hero';
|
||||||
import {BackendService} from './backend.service';
|
import {BackendService} from './backend.service';
|
||||||
import {Logger} from './logger.service';
|
import {Logger} from './logger.service';
|
||||||
|
@ -7,7 +7,7 @@ import {Logger} from './logger.service';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HeroService {
|
export class HeroService {
|
||||||
constructor(private _backend: BackendService, private _logger:Logger){}
|
constructor(private _backend: BackendService, private _logger:Logger){}
|
||||||
|
|
||||||
getHeroes() {
|
getHeroes() {
|
||||||
// TODO return as a promise
|
// TODO return as a promise
|
||||||
let heroes = <Hero[]> this._backend.getAll(Hero);
|
let heroes = <Hero[]> this._backend.getAll(Hero);
|
|
@ -1,4 +1,4 @@
|
||||||
import {Injectable} from 'angular2/angular2';
|
import {Injectable} from 'angular2/core';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class Logger {
|
export class Logger {
|
|
@ -2,8 +2,8 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Intro to Angular 2</title>
|
<title>Intro to Angular 2</title>
|
||||||
<script src="../node_modules/systemjs/dist/system.src.js"></script>
|
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||||
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
|
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
|
||||||
<script>
|
<script>
|
||||||
System.config({
|
System.config({
|
||||||
packages: {'app': {defaultExtension: 'js'}}
|
packages: {'app': {defaultExtension: 'js'}}
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<hero-list>Loading...</hero-list>
|
<my-app>Loading...</my-app>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -0,0 +1,40 @@
|
||||||
|
0 info it worked if it ends with ok
|
||||||
|
1 verbose cli [ 'C:\\Program Files\\nodejs\\node.exe',
|
||||||
|
1 verbose cli 'C:\\Users\\wardb\\AppData\\Roaming\\npm\\node_modules\\npm\\bin\\npm-cli.js',
|
||||||
|
1 verbose cli 'run',
|
||||||
|
1 verbose cli 'tsc:w' ]
|
||||||
|
2 info using npm@2.14.7
|
||||||
|
3 info using node@v4.2.1
|
||||||
|
4 verbose run-script [ 'pretsc:w', 'tsc:w', 'posttsc:w' ]
|
||||||
|
5 info pretsc:w angular2-template-syntax@1.0.0
|
||||||
|
6 info tsc:w angular2-template-syntax@1.0.0
|
||||||
|
7 verbose unsafe-perm in lifecycle true
|
||||||
|
8 info angular2-template-syntax@1.0.0 Failed to exec tsc:w script
|
||||||
|
9 verbose stack Error: angular2-template-syntax@1.0.0 tsc:w: `tsc -w`
|
||||||
|
9 verbose stack Exit status 3221225786
|
||||||
|
9 verbose stack at EventEmitter.<anonymous> (C:\Users\wardb\AppData\Roaming\npm\node_modules\npm\lib\utils\lifecycle.js:214:16)
|
||||||
|
9 verbose stack at emitTwo (events.js:87:13)
|
||||||
|
9 verbose stack at EventEmitter.emit (events.js:172:7)
|
||||||
|
9 verbose stack at ChildProcess.<anonymous> (C:\Users\wardb\AppData\Roaming\npm\node_modules\npm\lib\utils\spawn.js:24:14)
|
||||||
|
9 verbose stack at emitTwo (events.js:87:13)
|
||||||
|
9 verbose stack at ChildProcess.emit (events.js:172:7)
|
||||||
|
9 verbose stack at maybeClose (internal/child_process.js:818:16)
|
||||||
|
9 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
|
||||||
|
10 verbose pkgid angular2-template-syntax@1.0.0
|
||||||
|
11 verbose cwd c:\github\angular.io.ideablade\public\docs\_examples\architecture\ts
|
||||||
|
12 error Windows_NT 10.0.10586
|
||||||
|
13 error argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Users\\wardb\\AppData\\Roaming\\npm\\node_modules\\npm\\bin\\npm-cli.js" "run" "tsc:w"
|
||||||
|
14 error node v4.2.1
|
||||||
|
15 error npm v2.14.7
|
||||||
|
16 error code ELIFECYCLE
|
||||||
|
17 error angular2-template-syntax@1.0.0 tsc:w: `tsc -w`
|
||||||
|
17 error Exit status 3221225786
|
||||||
|
18 error Failed at the angular2-template-syntax@1.0.0 tsc:w script 'tsc -w'.
|
||||||
|
18 error This is most likely a problem with the angular2-template-syntax package,
|
||||||
|
18 error not with npm itself.
|
||||||
|
18 error Tell the author that this fails on your system:
|
||||||
|
18 error tsc -w
|
||||||
|
18 error You can get their info via:
|
||||||
|
18 error npm owner ls angular2-template-syntax
|
||||||
|
18 error There is likely additional logging output above.
|
||||||
|
19 verbose exit [ 1, true ]
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "angular2-template-syntax",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"tsc": "tsc",
|
||||||
|
"tsc:w": "tsc -w",
|
||||||
|
"lite": "lite-server",
|
||||||
|
"both": "concurrent \"npm run tsc:w\" \"npm run lite\" "
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
|
@ -1,12 +1,16 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES5",
|
"target": "ES5",
|
||||||
"module": "commonjs",
|
"module": "system",
|
||||||
|
"moduleResolution": "node",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"removeComments": false,
|
"removeComments": false,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"suppressImplicitAnyIndexErrors": true
|
"suppressImplicitAnyIndexErrors": true
|
||||||
}
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
}
|
}
|
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"name": "angular2-template-syntax",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"tsc": "tsc -p src -w",
|
|
||||||
"start": "live-server --open=src"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"angular2": "2.0.0-alpha.46",
|
|
||||||
"systemjs": "0.19.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"live-server": "^0.8.1",
|
|
||||||
"typescript": "^1.6.2"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
import {bootstrap} from 'angular2/angular2';
|
|
||||||
import {BackendService} from './backend.service';
|
|
||||||
import {HeroService} from './hero.service';
|
|
||||||
import {Logger} from './logger.service';
|
|
||||||
import {HeroListComponent} from './hero-list.component';
|
|
||||||
|
|
||||||
// #docregion bootstrap
|
|
||||||
bootstrap(HeroListComponent, [
|
|
||||||
BackendService, HeroService, Logger
|
|
||||||
]);
|
|
||||||
// #enddocregion bootstrap
|
|
|
@ -1,9 +0,0 @@
|
||||||
<hr>
|
|
||||||
<h4>{{hero.name}} Detail</h4>
|
|
||||||
<div>Id: {{hero.id}}</div>
|
|
||||||
<div>Name:
|
|
||||||
<!-- #docregion ng-model -->
|
|
||||||
<input [(ng-model)]="hero.name">
|
|
||||||
<!-- #enddocregion ng-model -->
|
|
||||||
</div>
|
|
||||||
<div>Power:<input [(ng-model)]="hero.power"></div>
|
|
|
@ -1,12 +0,0 @@
|
||||||
<!--#docregion binding -->
|
|
||||||
<div ... >{{hero.name}}</div>
|
|
||||||
<hero-detail ... [hero]="selectedHero"></hero-detail>
|
|
||||||
<div ... (click)="selectHero(hero)></div>
|
|
||||||
|
|
||||||
<!--#enddocregion binding -->
|
|
||||||
|
|
||||||
<!--#docregion structural -->
|
|
||||||
<div *ng-for="#hero of heroes" ...></div>
|
|
||||||
<hero-detail *ng-if="selectedHero" ...></hero-detail>
|
|
||||||
|
|
||||||
<!--#enddocregion structural -->
|
|
|
@ -1,8 +0,0 @@
|
||||||
<!-- #docregion -->
|
|
||||||
<h2>Hero List</h2>
|
|
||||||
|
|
||||||
<div *ng-for="#hero of heroes" (click)="selectHero(hero)">
|
|
||||||
{{hero.name}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hero-detail *ng-if="selectedHero" [hero]="selectedHero"></hero-detail>
|
|
|
@ -8,7 +8,11 @@
|
||||||
"cheatsheet": {
|
"cheatsheet": {
|
||||||
"title": "Angular Cheat Sheet"
|
"title": "Angular Cheat Sheet"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"architecture": {
|
||||||
|
"title": "Architecture Overview"
|
||||||
|
},
|
||||||
|
|
||||||
"displaying-data": {
|
"displaying-data": {
|
||||||
"title": "Displaying Data",
|
"title": "Displaying Data",
|
||||||
"intro": "In Angular, we display data by binding component properties to elements in HTML templates using interpolation and other forms of Property Binding."
|
"intro": "In Angular, we display data by binding component properties to elements in HTML templates using interpolation and other forms of Property Binding."
|
||||||
|
|
|
@ -0,0 +1,523 @@
|
||||||
|
include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
|
:marked
|
||||||
|
Angular 2 is a framework to help us build client applications in HTML and JavaScript.
|
||||||
|
|
||||||
|
The framework consists of several cooperating libraries, some of them core and some optional.
|
||||||
|
|
||||||
|
We write applications by composing HTML *templates* with Angularized-markup,
|
||||||
|
writing *component* classes to manage those templates, adding application logic in *services*,
|
||||||
|
and handing the top root component to Angular's *bootstrapper*.
|
||||||
|
|
||||||
|
Angular takes over, presenting our application content in a browser and responding to user interactions
|
||||||
|
according to the instructions we provided.
|
||||||
|
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/airplane.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
Of course there is more to it than this.
|
||||||
|
We're cruising at high altitude in this overview.
|
||||||
|
We're looking for landmarks. We should expect the object below to be fuzzy and obscured by occasional clouds.
|
||||||
|
Details become more clear and precise when we land in the chapters themselves.
|
||||||
|
<br clear="all">
|
||||||
|
|
||||||
|
:marked
|
||||||
|
An Angular 2 application rests on eight main building blocks:
|
||||||
|
1. [Module](#module)
|
||||||
|
1. [Component](#component)
|
||||||
|
1. [Template](#template)
|
||||||
|
1. [Metadata](#metadata)
|
||||||
|
1. [Data Binding](#data-binding)
|
||||||
|
1. [Service](#service)
|
||||||
|
1. [Directive](#directive)
|
||||||
|
1. [Dependency Injection](#dependency-injection)
|
||||||
|
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/overview2.png" alt="overview" style="margin-left:-40px;" width="700")
|
||||||
|
:marked
|
||||||
|
Learn these eight and we're on our way.
|
||||||
|
|
||||||
|
.l-sub-section
|
||||||
|
:marked
|
||||||
|
The code referenced in this chapter is available as a [live example](/resources/live-examples/architecture/ts/plnkr.html).
|
||||||
|
<a id="module"></a>
|
||||||
|
.l-main-section
|
||||||
|
:marked
|
||||||
|
## The Module
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
Angular apps are modular.
|
||||||
|
|
||||||
|
In general we assemble our application from many **modules**.
|
||||||
|
|
||||||
|
A typical module is a cohesive block of code dedicated to a single purpose.
|
||||||
|
A module **exports** something of value in that code, typically one thing such as a class.
|
||||||
|
<br clear="all"><br>
|
||||||
|
Perhaps the first module we meet is a module that exports a *component* class.
|
||||||
|
The component is one of the basic Angular blocks, we write a lot of them,
|
||||||
|
and we'll talk about components in the next segment. For the moment it is enough to know that a
|
||||||
|
component class is the kind of thing we'd export from a module.
|
||||||
|
|
||||||
|
Most applications have an `AppComponent`. By convention, we'll find it in a file named `app.component.ts`.
|
||||||
|
Look inside such a file and we'll see an `export` statement like this one.
|
||||||
|
+makeExample('architecture/ts/app/app.component.ts', 'export', 'app/app.component.ts (excerpt)')(format=".")
|
||||||
|
:marked
|
||||||
|
The `export` statement tells TypeScript that is a module whose
|
||||||
|
`AppComponent` class is public and accessible to other modules of the application
|
||||||
|
|
||||||
|
When we need a reference to the `AppComponent`, we **import** it like this:
|
||||||
|
+makeExample('architecture/ts/app/boot.ts', 'import', 'app/boot.ts (excerpt)')(format=".")
|
||||||
|
:marked
|
||||||
|
The `import` statement tells the system it can get an `AppComponent` from a module named `app.component`
|
||||||
|
located in a neighboring file.
|
||||||
|
The **module name** (AKA module id) is often the same as the filename without its extension.
|
||||||
|
### Library Modules
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/library-module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
Some modules are libraries of other modules.
|
||||||
|
|
||||||
|
Angular itself ships as a collection of library modules.
|
||||||
|
Each Angular library is actually a facade over several feature modules that belong together as a group.
|
||||||
|
|
||||||
|
The `angular2/core` library is the primary Angular library module from which we get most of what we need.
|
||||||
|
<br clear="all">
|
||||||
|
|
||||||
|
There are other important Angular library modules too such as `angular2/common`, `angular2/router`, and `angular2/http`.
|
||||||
|
|
||||||
|
We import what we need from an Angular library module in much the same way.
|
||||||
|
For example, we import the Angular **`Component` *function*** from the *angular2/core* module like this:
|
||||||
|
+makeExample('architecture/ts/app/app.component.ts', 'import')(format=".")
|
||||||
|
:marked
|
||||||
|
Compare that syntax to our previous import of `AppComponent`.
|
||||||
|
+makeExample('architecture/ts/app/boot.ts', 'import')(format=".")
|
||||||
|
:marked
|
||||||
|
Notice the difference?
|
||||||
|
In the first case, when importing from an Angular library module,
|
||||||
|
the import statement refers to the bare module name, `angular2/core`, *without a path prefix*.
|
||||||
|
|
||||||
|
When we import from one of *our* own files, we prefix the module name with the file path.
|
||||||
|
In this example we specify a relative file path (./). That means the
|
||||||
|
source module is in the same folder (./) as the module importing it.
|
||||||
|
We could path up and around the application folder structure if the source module were somewhere else.
|
||||||
|
.l-sub-section
|
||||||
|
:marked
|
||||||
|
We import and export in the ECMAScript 2015 (ES2015) module syntax.
|
||||||
|
Learn more about that syntax [here](http://www.2ality.com/2014/09/es6-modules-final.html)
|
||||||
|
and many other places on the web.
|
||||||
|
|
||||||
|
The infrastructure *behind* module loading and importing is an important subject.
|
||||||
|
But it's a subject outside the scope of this introduction to Angular.
|
||||||
|
While we're focused on our application, *import* and *export*
|
||||||
|
is about all we need to know.
|
||||||
|
:marked
|
||||||
|
The key take aways are:
|
||||||
|
* Angular apps are composed of modules.
|
||||||
|
* Modules export things — classes, function, values — that other modules import.
|
||||||
|
* We prefer to write our application as a collection of modules, each module exporting one thing.
|
||||||
|
|
||||||
|
The first module we write will most likely export a component.
|
||||||
|
.l-main-section
|
||||||
|
<a id="component"></a>
|
||||||
|
:marked
|
||||||
|
## The Component
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/hero-component.png" alt="Component" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
A **Component** controls a patch of screen real estate that we could call a *view*.
|
||||||
|
The shell at the application root with navigation links, that list of heroes, the hero editor ...
|
||||||
|
they're all views controlled by Components.
|
||||||
|
|
||||||
|
We define a Component's application logic - what it does to support the view - inside a class.
|
||||||
|
The class interacts with the view through an API of properties and methods.
|
||||||
|
|
||||||
|
<a id="component-code"></a>
|
||||||
|
A `HeroListComponent`, for example, might have a `heroes` property that returns an array of heroes
|
||||||
|
that it acquired from a service.
|
||||||
|
It might have a `selectHero()` method that sets a `selectedHero` property when the user click on a hero from that list.
|
||||||
|
It might be a class like this:
|
||||||
|
|
||||||
|
+makeExample('architecture/ts/app/hero-list.component.ts', 'class', 'app/hero-list.component.ts')
|
||||||
|
:marked
|
||||||
|
Angular creates, updates, and destroys components as the user moves through the application.
|
||||||
|
The developer can take action at each moment in this lifecycle through optional [Lifecycle Hooks](#).
|
||||||
|
.l-sub-section
|
||||||
|
:marked
|
||||||
|
We're not showing those hooks in this example
|
||||||
|
but we are making a mental note to find out about them later.
|
||||||
|
|
||||||
|
We may wonder who is calling that constructor? Who provides the service parameter?
|
||||||
|
For the moment, have faith that Angular will call the constructor and deliver an
|
||||||
|
appropriate `HeroService` when we need it.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
<a id="template"></a>
|
||||||
|
:marked
|
||||||
|
## The Template
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/template.png" alt="Template" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
We define a Component's view with its companion **template**. A template is a form of HTML
|
||||||
|
that tells Angular how to render the Component.
|
||||||
|
|
||||||
|
A template looks like regular HTML much of the time ... and then it gets a bit strange. Here is a
|
||||||
|
template for our `HeroList` component
|
||||||
|
+makeExample('architecture/ts/app/hero-list.component.html',null,'app/hero-list.component.html')
|
||||||
|
:marked
|
||||||
|
We recognize `<h2>` and `<div>`.
|
||||||
|
But there's other markup that no one told us about in school.
|
||||||
|
What is`*ngFor`, {{hero.name}}, `(click)`, `[hero]`, and `<hero-detail>`?
|
||||||
|
These are examples of Angular's [template syntax](template-syntax.html).
|
||||||
|
We will grow accustomed to that syntax and may even learn to love it.
|
||||||
|
We'll begin to explain it in a moment.
|
||||||
|
|
||||||
|
Before we do, focus attention on the last line.
|
||||||
|
The `<hero-detail>` tag is a custom element representing the `HeroDetailComponent`.
|
||||||
|
|
||||||
|
The `HeroDetailComponent` is a *different* component than the `HeroListComponent` we've been reviewing.
|
||||||
|
The `HeroDetailComponent` (code not shown) presents facts about a particular hero, the
|
||||||
|
hero that the user selects from the list presented by the the `HeroListComponent`.
|
||||||
|
The `HeroDetailComponent` is a **child** of the the `HeroListComponent`.
|
||||||
|
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/component-tree.png" alt="Metadata" align="left" style="width:300px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
Notice how `<hero-detail>` rests comfortably among the HTML elements we already know.
|
||||||
|
We can mix ... and will mix ... our custom components with native HTML in the same layouts.
|
||||||
|
|
||||||
|
And in this manner we can and will compose complex component trees to build out our richly featured application.
|
||||||
|
<br clear="all">
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
<a id="metadata"></a>
|
||||||
|
:marked
|
||||||
|
## Angular Metadata
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/metadata.png" alt="Metadata" align="left" style="width:150px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
<p style="padding-top:10px">Metadata tells Angular how to process a class.</p>
|
||||||
|
<br clear="all">
|
||||||
|
:marked
|
||||||
|
[Looking back](#component-code) at the `HeroListComponent`, we see that it's just a class.
|
||||||
|
There is no evidence of a framework, no "Angular" in it at all.
|
||||||
|
|
||||||
|
In fact, it really is *just a class*. It's not a component until we *tell Angular about it*.
|
||||||
|
|
||||||
|
We tell Angular that `HeroListComponent` is a component by attaching **metadata** to the class.
|
||||||
|
|
||||||
|
The easy way to attach metadata in TypeScript is with a **decorator**.
|
||||||
|
Here's some metadata for `HeroListComponent`:
|
||||||
|
+makeExample('architecture/ts/app/hero-list.component.ts', 'metadata', 'app/hero-list.component.ts (metadata)')
|
||||||
|
:marked
|
||||||
|
Here we see the `@Component` decorator which (no surprise) identifies the class
|
||||||
|
immediately below it as a Component class.
|
||||||
|
|
||||||
|
A decorator is a function. Decorators often have a configuration parameter.
|
||||||
|
The `@Component` decorator takes a required configuration object with the
|
||||||
|
information Angular needs to create and present the component and its view.
|
||||||
|
|
||||||
|
Here we see a few of the possible `@Component` configuration options:
|
||||||
|
|
||||||
|
* `selector` - a css selector that tells Angular to create and insert an instance of this component
|
||||||
|
where it finds a `<hero-list>` tag in *parent* HTML.
|
||||||
|
If the template of the application shell (a Component) contained
|
||||||
|
<div style="margin-left:30px">
|
||||||
|
code-example(language="html").
|
||||||
|
<hero-list></hero-list>
|
||||||
|
</div>
|
||||||
|
:marked
|
||||||
|
>Angular inserts an instance of the `HeroListComponent` view between those tags.
|
||||||
|
|
||||||
|
* `templateUrl` - the address of this component's template which we showed [above](#the-template).
|
||||||
|
|
||||||
|
* `directives` - an array of the Components or Directives that *this* template requires.
|
||||||
|
We saw in the last line of our template that we expect Angular to insert a `HeroDetailComponent`
|
||||||
|
in the space indicated by `<hero-detail>` tags.
|
||||||
|
Angular will do so only if we mention the `HeroDetailComponent` in this `directives` array.
|
||||||
|
|
||||||
|
* `providers` - an array of **dependency injection providers** for services that the component requires.
|
||||||
|
This is one way to tell Angular that our component's constructor requires a `HeroService`
|
||||||
|
so it can get the list of heroes to display. We'll get to dependency injection in a moment.
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/template-metadata-component.png" alt="Metadata" align="left" style="height:200px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
The `@Component` function takes the configuration object and turns it into metadata that it attaches
|
||||||
|
to the component class definition. Angular discovers this metadata at runtime and thus knows how to do "the right thing".
|
||||||
|
|
||||||
|
The template, metadata, and component together describe the view.
|
||||||
|
|
||||||
|
We apply other metadata decorators in a similar fashion to guide Angular behavior.
|
||||||
|
The `@Injectable`, `@Input`, `@Output`, `@RouterConfig` are a few of the more popular decorators
|
||||||
|
we'll master as our Angular knowledge grows.
|
||||||
|
<br clear="all">
|
||||||
|
:marked
|
||||||
|
The architectural take-away is that we must add metadata to our code
|
||||||
|
so that Angular knows what to do.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
<a id="data-binding"></a>
|
||||||
|
:marked
|
||||||
|
## Data Binding
|
||||||
|
Without a framework, we would be responsible for pushing data values into the HTML controls and turning user responses
|
||||||
|
into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone and a nightmare to
|
||||||
|
read as the experienced jQuery programmer can attest
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/databinding.png" alt="Data Binding" style="width:220px; float:left; margin-left:-40px;margin-right:20px" )
|
||||||
|
:marked
|
||||||
|
Angular supports **data binding**,
|
||||||
|
a mechanism for coordinating parts of a template with parts of a component.
|
||||||
|
We add binding markup to the template HTML to tell Angular how to connect both sides.
|
||||||
|
|
||||||
|
There are four forms of data binding syntax. Each form has a direction - to the DOM, from the DOM, or in both directions -
|
||||||
|
as indicated by the arrows in the diagram.
|
||||||
|
<br clear="all">
|
||||||
|
:marked
|
||||||
|
We saw three forms of data binding in our [example](#template) template:
|
||||||
|
+makeExample('architecture/ts/app/hero-list.component.1.html', 'binding', 'app/hero-list.component (excerpt)')(format=".")
|
||||||
|
:marked
|
||||||
|
* The {{hero.name}} "[interpolation](displaying-data.html#interpolation)"
|
||||||
|
displays the component's `hero.name` property value within the `<div>` tags.
|
||||||
|
|
||||||
|
* The `[hero]` [property binding](template-syntax.html#property-binding) passes the `selectedHero` from
|
||||||
|
the parent `HeroListComponent` to the `hero` property of the child `HeroDetailComponent`.
|
||||||
|
|
||||||
|
* The `(click)` [event binding](user-input.html#click) calls the Component's `selectHero` method when the user clicks
|
||||||
|
on a hero's name
|
||||||
|
|
||||||
|
**Two-way data binding** is an important fourth form
|
||||||
|
that combines property and event binding in a single notation using the `ngModel` directive.
|
||||||
|
We didn't have a two-way binding in the `HeroListComponent` template;
|
||||||
|
here's an example from the `HeroDetailComponent` template (not shown):
|
||||||
|
|
||||||
|
+makeExample('architecture/ts/app/hero-detail.component.html', 'ngModel')(format=".")
|
||||||
|
:marked
|
||||||
|
In two-way binding, a data property value flows to the input box from the component as with property binding.
|
||||||
|
The user's changes also flow back to the component, resetting the property to the latest value,
|
||||||
|
as with event binding.
|
||||||
|
|
||||||
|
Angular processes *all* data bindings once per JavaScript event cycle,
|
||||||
|
depth-first from the root of the application component tree.
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/component-databinding.png" alt="Data Binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
We don't know all the details yet
|
||||||
|
but it's clear from these examples that data binding plays an important role in communication
|
||||||
|
between a template and its component ...
|
||||||
|
<br clear="all">
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/parent-child-binding.png" alt="Parent/Child binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
... ***and*** between parent and child components
|
||||||
|
<br clear="all">
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
<a id="directive"></a>
|
||||||
|
:marked
|
||||||
|
## The Directive
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/directive.png" alt="Parent child" style="float:left; width:150px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
Our Angular templates are *dynamic*. When Angular renders them, it transforms the DOM
|
||||||
|
according to the instructions given by a **directive**.
|
||||||
|
|
||||||
|
A directive is a class with directive metadata. In TypeScript we'd apply the `@Directive` decorator
|
||||||
|
to attach metadata to the class.
|
||||||
|
<br clear="all">
|
||||||
|
:marked
|
||||||
|
We already met one form of directive: the component. A component is a *directive-with-a-template*
|
||||||
|
and the `@Component` decorator is actually a `@Directive` decorator extended with template-oriented features.
|
||||||
|
|
||||||
|
.l-sub-section
|
||||||
|
:marked
|
||||||
|
While the **component is technically a directive**,
|
||||||
|
it is so distinctive and central to Angular applications that we chose
|
||||||
|
to separate the component from the directive in our architectural overview.
|
||||||
|
:marked
|
||||||
|
There are two *other* kinds of directives as well that we call "structural" and "attribute" directives.
|
||||||
|
|
||||||
|
They tend to appear within an element tag like attributes,
|
||||||
|
sometimes by name but more often as the target of an assignment or a binding.
|
||||||
|
|
||||||
|
**Structural** directives alter layout by adding, removing, and replacing elements in DOM.
|
||||||
|
|
||||||
|
We see two built-in structural directives at play in our [example](#template) template:
|
||||||
|
+makeExample('architecture/ts/app/hero-list.component.1.html', 'structural')(format=".")
|
||||||
|
:marked
|
||||||
|
* [`*ngFor`](displaying-data.html#ngFor) tells Angular to stamp out one `<div>` per hero in the `heroes` list.
|
||||||
|
* [`*ngIf`](displaying-data.html#ngIf) includes the `HeroDetail` component only if a selected hero exists.
|
||||||
|
|
||||||
|
**Attribute** directives alter the appearance or behavior of an existing element.
|
||||||
|
In templates they look like regular HTML attributes, hence the name.
|
||||||
|
|
||||||
|
The `ngModel` directive, which implements two-way data binding, is an example of an attribute directive.
|
||||||
|
+makeExample('architecture/ts/app/hero-detail.component.html', 'ngModel')(format=".")
|
||||||
|
:marked
|
||||||
|
It modifies the behavior of an existing element (typically an `<input>`)
|
||||||
|
by setting its display value property and responding to change events.
|
||||||
|
|
||||||
|
Angular ships with a small number of other directives that either alter the layout structure
|
||||||
|
(e.g. [ngSwitch](template-syntax.html#ngSwitch))
|
||||||
|
or modify aspects of DOM elements and components
|
||||||
|
(e.g. [ngStyle](template-syntax.html#ngStyle) and [ngClass](template-syntax.html#ngClass)).
|
||||||
|
|
||||||
|
And of course we can write our own directives.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
<a id="service"></a>
|
||||||
|
:marked
|
||||||
|
## The Service
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/service.png" alt="Service" style="float:left; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
"Service" is a broad category encompassing any value, function or feature that our application needs.
|
||||||
|
|
||||||
|
Almost anything can be a service.
|
||||||
|
A service is typically a class with a narrow, well-defined purpose. It should do something specific and do it well.
|
||||||
|
<br clear="all">
|
||||||
|
:marked
|
||||||
|
Examples include:
|
||||||
|
* logging service
|
||||||
|
* data service
|
||||||
|
* message bus
|
||||||
|
* tax calculator
|
||||||
|
* application configuration
|
||||||
|
|
||||||
|
There is nothing specifically "Angular" about services. Angular itself has no definition of a "service".
|
||||||
|
There is no service base class, no place to register a "service".
|
||||||
|
|
||||||
|
Yet services are fundamental to any Angular application. Our components are big consumers of service.
|
||||||
|
|
||||||
|
We prefer our component classes lean. Our components don't fetch data from the server,
|
||||||
|
they don't validate user input, they don't log directly to console. They delegate such task to services.
|
||||||
|
|
||||||
|
A component's job is to enable the user experience and nothing more. It mediates between the view (rendered by the template)
|
||||||
|
and the application logic (which often includes some notion of a "model").
|
||||||
|
A good component presents properties and methods for data binding.
|
||||||
|
It delegates everything non-trivial to services.
|
||||||
|
|
||||||
|
Angular doesn't *enforce* these principles.
|
||||||
|
It won't complain if write a "kitchen sink" component with 3000 lines.
|
||||||
|
|
||||||
|
Angular does help us *follow* these principles ... by making it easy to factor our
|
||||||
|
application logic into services and make those services available to components through *dependency injection*.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
<a id="dependency-injection"></a>
|
||||||
|
:marked
|
||||||
|
## Dependency Injection
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/dependency-injection.png" alt="Service" style="float:left; width:200px; margin-left:-40px;margin-right:10px" )
|
||||||
|
:marked
|
||||||
|
"Dependency Injection" is a way to supply a new instance of a class
|
||||||
|
with the fully-formed dependencies it requires. Most dependencies are services.
|
||||||
|
Angular uses dependency injection to provide new components with the services they need.
|
||||||
|
<br clear="all">
|
||||||
|
:marked
|
||||||
|
In TypeScript, Angular can tell which services a component needs by looking at the types of its constructor parameters.
|
||||||
|
For example, the constructor of our `HeroListComponent` needs the `HeroService`:
|
||||||
|
+makeExample('architecture/ts/app/hero-list.component.ts', 'ctor', 'app/hero-list.component (constructor)')(format=".")
|
||||||
|
:marked
|
||||||
|
When Angular creates a component, it first asks an **Injector** for
|
||||||
|
the services that the component requires.
|
||||||
|
|
||||||
|
An `Injector` maintains a container of service instances that it has previously created.
|
||||||
|
If a requested service instance is not in the container, the injector makes one and adds it to the container
|
||||||
|
before returning the service to Angular.
|
||||||
|
When all requested services have been resolved and returned,
|
||||||
|
Angular can call the component's constructor with those services as arguments.
|
||||||
|
This is what we mean by *dependency injection*.
|
||||||
|
|
||||||
|
The process of `HeroService` injection looks a bit like this:
|
||||||
|
figure
|
||||||
|
img(src="/resources/images/devguide/architecture/injector-injects.png" alt="Service" )
|
||||||
|
:marked
|
||||||
|
If the `Injector` doesn't have a `HeroService`, how does it know how to make one?
|
||||||
|
|
||||||
|
In brief, we must have previously registered a **provider** of the `HeroService` with the `Injector`.
|
||||||
|
A provider is something that can create or return a service, typically the service class itself.
|
||||||
|
|
||||||
|
We can register providers at any level of the application component tree.
|
||||||
|
We often do so at the root when we bootstrap the application so that
|
||||||
|
the same instance of a service is available everywhere.
|
||||||
|
+makeExample('architecture/ts/app/boot.ts', 'bootstrap','app/boot.ts (excerpt)')(format=".")
|
||||||
|
:marked
|
||||||
|
Alternatively, we might register at a component level ...
|
||||||
|
+makeExample('architecture/ts/app/hero-list.component.ts', 'providers','app/hero-list.component.ts (excerpt)')(format=".")
|
||||||
|
:marked
|
||||||
|
... in which case we get a new instance of the
|
||||||
|
service with each new instance of that component.
|
||||||
|
|
||||||
|
We've vastly over-simplified dependency injection for this overview.
|
||||||
|
We can learn the full story in the [Dependency Injection](dependency-injection.html) chapter.
|
||||||
|
|
||||||
|
The points to remember are:
|
||||||
|
* dependency injection is wired into the framework and used everywhere.<br><br>
|
||||||
|
* the `Injector` is the main mechanism.
|
||||||
|
* an injector maintains a *container* of service instances that it created.
|
||||||
|
* an injector can create a new service instance from a *provider*.
|
||||||
|
* a *provider* is a recipe for creating a service.
|
||||||
|
|
||||||
|
* we register *providers* with injectors.
|
||||||
|
|
||||||
|
<a id="other-stuff"></a>
|
||||||
|
.l-main-section
|
||||||
|
:marked
|
||||||
|
## Wrap up
|
||||||
|
We've learned just a bit about the eight main building blocks of an Angular application
|
||||||
|
|
||||||
|
1. [Module](#module)
|
||||||
|
1. [Component](#component)
|
||||||
|
1. [Template](#template)
|
||||||
|
1. [Metadata](#metadata)
|
||||||
|
1. [Data Binding](#data-binding)
|
||||||
|
1. [Service](#service)
|
||||||
|
1. [Directive](#directive)
|
||||||
|
1. [Dependency Injection](#dependency-injection)
|
||||||
|
|
||||||
|
That's a foundation for everything else in an Angular application
|
||||||
|
and it's more than enough to get going.
|
||||||
|
But it doesn't include everything we'll need or want to know.
|
||||||
|
|
||||||
|
<a id="other-stuff"></a>
|
||||||
|
.l-main-section
|
||||||
|
:marked
|
||||||
|
## The Other Stuff
|
||||||
|
|
||||||
|
Here is a brief, alphabetical list of other important Angular features and services.
|
||||||
|
Most of them are covered in this Developers Guide (or soon will be):
|
||||||
|
|
||||||
|
>**Animations** - A forthcoming animation library makes it easy for developers to animate component behavior
|
||||||
|
without deep knowledge of animation techniques or css.
|
||||||
|
|
||||||
|
>**Bootstrap** - A method to configure and launch the root application component.
|
||||||
|
|
||||||
|
>**Change Detection** - Learn how Angular decides that a component property value has changed and
|
||||||
|
when to update the screen.
|
||||||
|
Learn how it uses **zones** to intercept asynchronous activity and run its change detection strategies.
|
||||||
|
|
||||||
|
>**Component Router** - With the Component Router service, users can navigate a multi-screen application
|
||||||
|
in a familiar web browsing style using URLs.
|
||||||
|
|
||||||
|
>**Events** - The DOM raise events. So can components and services. Angular offers mechanisms for
|
||||||
|
publishing and subscribing to events including an implementation of the [RxJS Observable](https://github.com/zenparsing/es-observable) proposal.
|
||||||
|
|
||||||
|
>**[Forms](forms.html)** - Support complex data entry scenarios with HTML-based validation and dirty checking.
|
||||||
|
|
||||||
|
>**HTTP** - Communicate with a server to get data, save data, and invoke server-side actions with this Angular HTTP client.
|
||||||
|
|
||||||
|
>**Lifecycle Hooks** - We can tap into key moments in the lifetime of a component, from its creation to its destruction,
|
||||||
|
by implementing the "Lifecycle Hook" interfaces.
|
||||||
|
|
||||||
|
>**[Pipes](pipes.html)** - Services that transform values for display.
|
||||||
|
We can put pipes in our templates to improve the user experience. For example,
|
||||||
|
this `currency` pipe expression,
|
||||||
|
<div style="margin-left:40px">
|
||||||
|
code-example(language="javascript" linenumbers=".").
|
||||||
|
price | currency:'USD':true'
|
||||||
|
</div>
|
||||||
|
:marked
|
||||||
|
>displays a price of "42.33" as `$42.33`.
|
||||||
|
|
||||||
|
>**[Testing](../testing/index.html)** - Angular provides a testing library for "unit testing" our application parts as they
|
||||||
|
interact with the Angular framework.
|
|
@ -1,7 +1,7 @@
|
||||||
include ../../../../_includes/_util-fns
|
include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The Developers Guide is a practical guide to Angular for experienced programmers who
|
The Developer Guide is a practical guide to Angular for experienced programmers who
|
||||||
are building client applications in HTML and JavaScript.
|
are building client applications in HTML and JavaScript.
|
||||||
figure
|
figure
|
||||||
img(src="/resources/images/devguide/intro/people.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
img(src="/resources/images/devguide/intro/people.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
||||||
|
@ -15,497 +15,76 @@ figure
|
||||||
* What are the essential Angular building blocks and how do they help?
|
* What are the essential Angular building blocks and how do they help?
|
||||||
* How do we minimize routine, mechanical coding in favor of declarative, higher level constructs without losing control?
|
* How do we minimize routine, mechanical coding in favor of declarative, higher level constructs without losing control?
|
||||||
|
|
||||||
This chapter begins the journey. It's an introduction to Angular in two parts.
|
This chapter begins the journey.
|
||||||
1. [How to read this guide](#how-to-read)
|
|
||||||
2. [An architecture overview](#architecture)
|
|
||||||
|
|
||||||
.l-main-section
|
|
||||||
<a id="how-to-read"></a>
|
<a id="how-to-read"></a>
|
||||||
:marked
|
:marked
|
||||||
# How to Read this Guide
|
# How to Read this Guide
|
||||||
The chapters of this guide target an Angular feature and how to use it to solve a programming problem.
|
The chapters of this guide target an Angular feature and how to use it to solve a programming problem.
|
||||||
|
|
||||||
|
## Chapters
|
||||||
|
|
||||||
|
The guide consists of chapters devoted to the challenges of building an application and
|
||||||
|
meeting those challenges with Angular.
|
||||||
|
|
||||||
|
A few early chapters are written as tutorials and are clearly marked as such.
|
||||||
|
Most chapters are *not* tutorials and do not explain every step necessary to build the accompanying sample.
|
||||||
|
These chapters highlight key points in code but generally don't include the entire source.
|
||||||
|
We can get that source by way of the live link to the chapter's code sample.
|
||||||
|
|
||||||
|
## Code Samples
|
||||||
|
|
||||||
Every chapter includes code snippets ... snippets we can reuse in our own applications.
|
Every chapter includes code snippets ... snippets we can reuse in our own applications.
|
||||||
Typically, these snippets are excerpts from a running sample application that accompanies the chapter.
|
Typically, these snippets are excerpts from a running sample application that accompanies the chapter.
|
||||||
We can often find a link to a live version of that sample near the top of the chapter ... like this one.
|
We usually find a link to a live version of that sample near the top of the chapter ... like this one.
|
||||||
|
|
||||||
[Live Example](/resources/live-examples/intro/ts/src/plnkr.html)
|
[Live Example](/resources/live-examples/architecture/ts/plnkr.html)
|
||||||
|
|
||||||
This link opens in a browser and runs the sample code supporting this chapter's architecture overview.
|
This link opens in a browser and runs the sample code supporting this chapter's architecture overview.
|
||||||
We can inspect, modify, save, and download the code.
|
We can inspect, modify, save, and download the code.
|
||||||
|
|
||||||
|
## Learning Path
|
||||||
|
We don't have to read this guide straight through. Most chapters stand on their own.
|
||||||
|
We can browse to any of them as our interest or some necessity moves us.
|
||||||
|
|
||||||
|
But there is a learning path for those of us who are new to Angular.
|
||||||
|
|
||||||
A few chapters are written as tutorials and are clearly marked as such.
|
1. Read the [Architecture Overview](architecture.html) to get the big picture.
|
||||||
Most chapters are *not* tutorials and do not explain how to build the accompanying sample.
|
|
||||||
These chapters highlight key points in code but generally don't include the entire source.
|
|
||||||
We can get that by way of the live link.
|
|
||||||
|
|
||||||
We don't have to read this guide straight through.
|
1. Step *outside* the guide and try the [QuickStart](../quickstart.html). The QuickStart is the "Hello, World" of Angular 2.
|
||||||
The "[Cheat Sheet](cheatsheet.html)" is a handy map to Angular overall.
|
|
||||||
A few early chapters are arranged sequentially and best read together to establish a foundation in Angular.
|
|
||||||
But most chapters stand on their own. We can browse to any of them as our interest or some necessity moves us.
|
|
||||||
|
|
||||||
There is a learning path for those of us who are new to Angular.
|
|
||||||
|
|
||||||
It starts *outside* the guide with the [QuickStart](../quickstart.html). The QuickStart is the "Hello, World" of Angular 2.
|
|
||||||
It shows us how to setup the libraries and tools we'll need to write *any* Angular app.
|
It shows us how to setup the libraries and tools we'll need to write *any* Angular app.
|
||||||
It ends with a "proof of life", a running Angular app.
|
|
||||||
|
|
||||||
The [Tutorial](../tutorial) is our next stop.
|
1. Follow the [Tutorial](../tutorial). The "Tour of Heroes" tutorial takes us step-by-step from where QuickStart leaves off
|
||||||
It walks us step-by-step from where QuickStart leaves off to a simple data-driven app. Simple, yes, but with
|
to a simple data-driven app.
|
||||||
the essential characteristics we'd expect of a professional application:
|
Simple, yes, but with the essential characteristics we'd expect of a professional application:
|
||||||
a sensible project structure, data binding, master/detail, services, dependency injection, navigation, and remote data access.
|
a sensible project structure, data binding, master/detail, services, dependency injection, navigation, and remote data access.
|
||||||
The final iteration of the "[Tour of Heroes](#toh)" is a positive answer to that most important question:
|
|
||||||
|
The final iteration of the "[Tour of Heroes](#toh)" is a positive answer to that most important question:
|
||||||
***can we build an Angular 2 application that does what we need it to do?***
|
***can we build an Angular 2 application that does what we need it to do?***
|
||||||
|
|
||||||
We suggest continuing from the "Tour of Heroes" tutorial to the early core chapters of this Developers Guide in the following order:
|
Return from the tutorial to the basic chapters of this Developers Guide.
|
||||||
1. [Displaying Data](displaying-data.html)
|
|
||||||
1. [User Input](user-input.html)
|
|
||||||
1. [Forms](forms.html)
|
|
||||||
1. [Dependency Injection](dependency-injection.html)
|
|
||||||
|
|
||||||
We might pause at that point to absorb what we've learned and perhaps experiment on our own before diving into [Template Syntax](template-syntax.html).
|
|
||||||
That chapter is rather dense. It's also essential reading at some point and
|
|
||||||
we will return to it frequently as we compose our HTML templates, both for understanding and as a reference.
|
|
||||||
|
|
||||||
Follow your own star from there, wherever it leads.
|
|
||||||
|
|
||||||
.l-main-section
|
|
||||||
<a id="architecture"></a>
|
|
||||||
:marked
|
|
||||||
# Architecture Overview
|
|
||||||
Angular 2 is a framework to help us build client applications in HTML and JavaScript.
|
|
||||||
|
|
||||||
The framework consists of several cooperating libraries, some of them core and some optional.
|
|
||||||
|
|
||||||
We write applications by composing HTML *templates* with Angularized-markup,
|
|
||||||
writing *component* classes to manage those templates, adding application logic in *services*,
|
|
||||||
and handing the top root component to Angular's *bootstrapper*.
|
|
||||||
|
|
||||||
Angular takes over, presenting our application content in a browser and responding to user interactions
|
|
||||||
according to the instructions we provided.
|
|
||||||
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/airplane.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
Of course there is more to it than this.
|
|
||||||
We're cruising at high altitude in this overview.
|
|
||||||
We're looking for landmarks. We should expect the object below to be fuzzy and obscured by occasional clouds.
|
|
||||||
Details become more clear and precise when we land in the chapters themselves.
|
|
||||||
<br clear="all">
|
|
||||||
|
|
||||||
:marked
|
|
||||||
An Angular 2 application rests on seven main building blocks:
|
|
||||||
1. [Component](#component)
|
|
||||||
1. [Template](#template)
|
|
||||||
1. [Metadata](#metadata)
|
|
||||||
1. [Data Binding](#data-binding)
|
|
||||||
1. [Directive](#directive)
|
|
||||||
1. [Service](#service)
|
|
||||||
1. [Dependency Injection](#dependency-injection)
|
|
||||||
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/overview.png" alt="overview" style="margin-left:-40px;" )
|
|
||||||
:marked
|
|
||||||
Learn these seven and we're on our way.
|
|
||||||
|
|
||||||
.l-main-section
|
|
||||||
<a id="component"></a>
|
|
||||||
:marked
|
|
||||||
## The Component
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/hero-component.png" alt="Component" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
A **Component** controls a patch of screen real estate that we could call a *view*.
|
|
||||||
The shell at the application root with navigation links, that list of heroes, the hero editor ...
|
|
||||||
they're all views controlled by Components.
|
|
||||||
|
|
||||||
We define a Component's application logic - what it does to support the view - inside a class.
|
|
||||||
The class interacts with the view through an API of properties and methods.
|
|
||||||
|
|
||||||
<a id="component-code"></a>
|
|
||||||
A `HeroListComponent`, for example, might have a `heroes` property that returns an array of heroes
|
|
||||||
that it acquired from a service.
|
|
||||||
It might have a `selectHero()` method that sets a `selectedHero` property when the user click on a hero from that list.
|
|
||||||
It might be a class like this:
|
|
||||||
|
|
||||||
+makeExample('intro/ts/src/app/hero-list.component.ts', 'class')
|
|
||||||
:marked
|
|
||||||
Angular creates, updates, and destroys components as the user moves through the application.
|
|
||||||
The developer can take action at each moment in this lifecycle through optional [Lifecycle Hooks](#).
|
|
||||||
.l-sub-section
|
|
||||||
:marked
|
|
||||||
We're not showing those hooks in this example
|
|
||||||
but we are making a mental note to find out about them later.
|
|
||||||
|
|
||||||
We may wonder who is calling that constructor? Who provides the service parameter?
|
1. [Displaying Data](displaying-data.html) explains how to get information on to the screen.
|
||||||
For the moment, have faith that Angular will call the constructor and deliver an
|
|
||||||
appropriate `HeroService` when we need it.
|
1. [User Input](user-input.html) covers the basics of responding to user behavior.
|
||||||
|
|
||||||
|
1. [Forms](forms.html) handle user data entry and validation within the UI.
|
||||||
|
|
||||||
|
1. [Dependency Injection](dependency-injection.html) is the way we build large, maintainable applications
|
||||||
|
from small, single purpose parts.
|
||||||
|
|
||||||
|
1. [Template Syntax](template-syntax.html) is a comprehensive study of Angular template HTML.
|
||||||
|
|
||||||
.l-main-section
|
With this foundation, we can read and understand any chapter in the guide.
|
||||||
<a id="template"></a>
|
|
||||||
:marked
|
|
||||||
## The Template
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/template.png" alt="Template" align="left" style="width:200px; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
We define a Component's view with its companion **template**. A template is a form of HTML
|
|
||||||
that tells Angular how to render the Component.
|
|
||||||
|
|
||||||
A template looks like regular HTML much of the time ... and then it gets a bit strange. Here is a
|
|
||||||
template for our `HeroList` component
|
|
||||||
+makeExample('intro/ts/src/app/hero-list.component.html')
|
|
||||||
:marked
|
|
||||||
We recognize `<h2>` and `<div>`.
|
|
||||||
But there's other markup that no one told us about in school.
|
|
||||||
What is`*ng-for`, <code>{‌{hero.name}}</code>, `(click)`, `[hero]`, and `<hero-detail>`?
|
|
||||||
These are examples of Angular's [template syntax](template-syntax.html).
|
|
||||||
We will grow accustomed to that syntax and may even learn to love it.
|
|
||||||
We'll begin to explain it in a moment.
|
|
||||||
|
|
||||||
Before we do, focus attention on the last line.
|
|
||||||
The `<hero-detail>` tag is a custom element representing the `HeroDetailComponent`.
|
|
||||||
|
|
||||||
The `HeroDetailComponent` is a *different* component than the `HeroListComponent` we've been reviewing.
|
|
||||||
The `HeroDetailComponent` (code not shown) presents facts about a particular hero, the
|
|
||||||
hero that the user selects from the list presented by the the `HeroListComponent`.
|
|
||||||
The `HeroDetailComponent` is a **child** of the the `HeroListComponent`.
|
|
||||||
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/component-tree.png" alt="Metadata" align="left" style="width:300px; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
Notice how `<hero-detail>` rests comfortably among the HTML elements we already know.
|
|
||||||
We can mix ... and will mix ... our custom components with native HTML in the same layouts.
|
|
||||||
|
|
||||||
And in this manner we can and will compose complex component trees to build out our richly featured application.
|
|
||||||
<br clear="all">
|
|
||||||
|
|
||||||
.l-main-section
|
|
||||||
<a id="metadata"></a>
|
|
||||||
:marked
|
|
||||||
## Angular Metadata
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/metadata.png" alt="Metadata" align="left" style="width:150px; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
<p style="padding-top:10px">Metadata tells Angular how to process a class.</p>
|
|
||||||
<br clear="all">
|
|
||||||
:marked
|
|
||||||
[Looking back](#component-code) at the `HeroListComponent`, we see that it's just a class.
|
|
||||||
There is no evidence of a framework, no "Angular" in it at all.
|
|
||||||
|
|
||||||
In fact, it really is *just a class*. It's not a component until we *tell Angular about it*.
|
|
||||||
|
|
||||||
We tell Angular that `HeroListComponent` is a component by attaching **metadata** to the class.
|
|
||||||
|
|
||||||
The easy way to attach metadata in TypeScript is with a **decorator**.
|
|
||||||
Here's some metadata for `HeroListComponent`:
|
|
||||||
+makeExample('intro/ts/src/app/hero-list.component.ts', 'metadata')
|
|
||||||
:marked
|
|
||||||
Here we see the `@Component` decorator which (no surprise) identifies the class
|
|
||||||
immediately below it as a Component class.
|
|
||||||
|
|
||||||
A decorator is a function. Decorators often have a configuration parameter.
|
|
||||||
The `@Component` decorator takes a required configuration object with the
|
|
||||||
information Angular needs to create and present the component and its view.
|
|
||||||
|
|
||||||
Here we see a few of the possible `@Component` configuration options:
|
|
||||||
|
|
||||||
* `selector` - a css selector that tells Angular to create and insert an instance of this component
|
|
||||||
where it finds a `<hero-list>` tag in *parent* HTML.
|
|
||||||
If the template of the application shell (a Component) contained
|
|
||||||
<div style="margin-left:30px">
|
|
||||||
code-example(language="html").
|
|
||||||
<hero-list></hero-list>
|
|
||||||
</div>
|
|
||||||
:marked
|
|
||||||
>Angular inserts an instance of the `HeroListComponent` view between those tags.
|
|
||||||
|
|
||||||
* `templateUrl` - the address of this component's template which we showed [above](#the-template).
|
|
||||||
|
|
||||||
* `directives` - an array of the Components or Directives that *this* template requires.
|
|
||||||
We saw in the last line of our template that we expect Angular to insert a `HeroDetailComponent`
|
|
||||||
in the space indicated by `<hero-detail>` tags.
|
|
||||||
Angular will do so only if we mention the `HeroDetailComponent` in this `directives` array.
|
|
||||||
|
|
||||||
* `providers` - an array of **dependency injection providers** for services that the component requires.
|
|
||||||
This is one way to tell Angular that our component's constructor requires a `HeroService`
|
|
||||||
so it can get the list of heroes to display. We'll get to dependency injection in a moment.
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/template-metadata-component.png" alt="Metadata" align="left" style="height:200px; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
The `@Component` function takes the configuration object and turns it into metadata that it attaches
|
|
||||||
to the component class definition. Angular discovers this metadata at runtime and thus knows how to do "the right thing".
|
|
||||||
|
|
||||||
The template, metadata, and component together describe the view.
|
|
||||||
|
|
||||||
We apply other metadata decorators in a similar fashion to guide Angular behavior.
|
|
||||||
The `@Injectable`, `@Input`, `@Output`, `@RouterConfig` are a few of the more popular decorators
|
|
||||||
we'll master as our Angular knowledge grows.
|
|
||||||
<br clear="all">
|
|
||||||
:marked
|
|
||||||
The architectural take-away is that we must add metadata to our code
|
|
||||||
so that Angular knows what to do.
|
|
||||||
|
|
||||||
.l-main-section
|
|
||||||
<a id="data-binding"></a>
|
|
||||||
:marked
|
|
||||||
## Data Binding
|
|
||||||
Without a framework, we would be responsible for pushing data values into the HTML controls and turning user responses
|
|
||||||
into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone and a nightmare to
|
|
||||||
read as the experienced jQuery programmer can attest
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/databinding.png" alt="Data Binding" style="width:220px; float:left; margin-left:-40px;margin-right:20px" )
|
|
||||||
:marked
|
|
||||||
Angular supports **data binding**,
|
|
||||||
a mechanism for coordinating parts of a template with parts of a component.
|
|
||||||
We add binding markup to the template HTML to tell Angular how to connect both sides.
|
|
||||||
|
|
||||||
There are four forms of data binding syntax. Each form has a direction - to the DOM, from the DOM, or in both directions -
|
|
||||||
as indicated by the arrows in the diagram.
|
|
||||||
<br clear="all">
|
|
||||||
:marked
|
|
||||||
We saw three forms of data binding in our [example](#template) template:
|
|
||||||
+makeExample('intro/ts/src/app/hero-list.component.1.html', 'binding')(format=".")
|
|
||||||
:marked
|
|
||||||
* The <code>{‌{hero.name}}</code> "[interpolation](displaying-data.html#interpolation)"
|
|
||||||
displays the component's `hero.name` property value within the `<div>` tags.
|
|
||||||
|
|
||||||
* The `[hero]` [property binding](template-syntax.html#property-binding) passes the `selectedHero` from
|
|
||||||
the parent `HeroListComponent` to the `hero` property of the child `HeroDetailComponent`.
|
|
||||||
|
|
||||||
* The `(click)` [event binding](user-input.html#click) calls the Component's `selectHero` method when the user clicks
|
|
||||||
on a hero's name
|
|
||||||
|
|
||||||
**Two-way data binding** is an important fourth form
|
|
||||||
that combines property and event binding in a single notation using the `ng-model` directive.
|
|
||||||
We didn't have a two-way binding in the `HeroListComponent` template;
|
|
||||||
here's an example from the `HeroDetailComponent` template (not shown):
|
|
||||||
|
|
||||||
+makeExample('intro/ts/src/app/hero-detail.component.html', 'ng-model')(format=".")
|
|
||||||
:marked
|
|
||||||
In two-way binding, a data property value flows to the input box from the component as with property binding.
|
|
||||||
The user's changes also flow back to the component, resetting the property to the latest value,
|
|
||||||
as with event binding.
|
|
||||||
|
|
||||||
Angular processes *all* data bindings once per JavaScript event cycle,
|
|
||||||
depth-first from the root of the application component tree.
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/component-databinding.png" alt="Data Binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
We don't know all the details yet
|
|
||||||
but it's clear from these examples that data binding plays an important role in communication
|
|
||||||
between a template and its component ...
|
|
||||||
<br clear="all">
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/parent-child-binding.png" alt="Parent/Child binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
... ***and*** between parent and child components
|
|
||||||
<br clear="all">
|
|
||||||
|
|
||||||
.l-main-section
|
|
||||||
<a id="directive"></a>
|
|
||||||
:marked
|
|
||||||
## The Directive
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/directive.png" alt="Parent child" style="float:left; width:150px; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
Our Angular templates are *dynamic*. When Angular renders them, it transforms the DOM
|
|
||||||
according to the instructions given by a **directive**.
|
|
||||||
|
|
||||||
A directive is a class with directive metadata. In TypeScript we'd apply the `@Directive` decorator
|
|
||||||
to attach metadata to the class.
|
|
||||||
<br clear="all">
|
|
||||||
:marked
|
|
||||||
We already met one form of directive: the component. A component is a *directive-with-a-template*
|
|
||||||
and the `@Component` decorator is actually a `@Directive` decorator extended with template-oriented features.
|
|
||||||
|
|
||||||
.l-sub-section
|
|
||||||
:marked
|
|
||||||
While the **component is technically a directive**,
|
|
||||||
it is so distinctive and central to Angular applications that we chose
|
|
||||||
to separate the component from the directive in our architectural overview.
|
|
||||||
:marked
|
|
||||||
There are two *other* kinds of directives as well that we call "structural" and "attribute" directives.
|
|
||||||
|
|
||||||
They tend to appear within an element tag like attributes,
|
|
||||||
sometimes by name but more often as the target of an assignment or a binding.
|
|
||||||
|
|
||||||
**Structural** directives alter layout by adding, removing, and replacing elements in DOM.
|
|
||||||
|
|
||||||
We see two built-in structural directives at play in our [example](#template) template:
|
|
||||||
+makeExample('intro/ts/src/app/hero-list.component.1.html', 'structural')(format=".")
|
|
||||||
:marked
|
|
||||||
* [`*ng-for`](displaying-data.html#ng-for) tells Angular to stamp out one `<div>` per hero in the `heroes` list.
|
|
||||||
* [`*ng-if`](displaying-data.html#ng-if) includes the `HeroDetail` component only if a selected hero exists.
|
|
||||||
|
|
||||||
**Attribute** directives alter the appearance or behavior of an existing element.
|
|
||||||
In templates they look like regular HTML attributes, hence the name.
|
|
||||||
|
|
||||||
The `ng-model` directive, which implements two-way data binding, is an example of an attribute directive.
|
|
||||||
+makeExample('intro/ts/src/app/hero-detail.component.html', 'ng-model')(format=".")
|
|
||||||
:marked
|
|
||||||
It modifies the behavior of an existing element (typically an `<input>`)
|
|
||||||
by setting its display value property and responding to change events.
|
|
||||||
|
|
||||||
Angular ships with a small number of other directives that either alter the layout structure
|
|
||||||
(e.g. [ng-switch](template-syntax.html#ng-switch))
|
|
||||||
or modify aspects of DOM elements and components
|
|
||||||
(e.g. [ng-style](template-syntax.html#ng-style) and [ng-class](template-syntax.html#ng-class)).
|
|
||||||
|
|
||||||
And of course we can write our own directives.
|
|
||||||
|
|
||||||
.l-main-section
|
|
||||||
<a id="service"></a>
|
|
||||||
:marked
|
|
||||||
## The Service
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/service.png" alt="Service" style="float:left; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
"Service" is a broad category encompassing any value, function or feature that our application needs.
|
|
||||||
|
|
||||||
Almost anything can be a service.
|
|
||||||
A service is typically a class with a narrow, well-defined purpose. It should do something specific and do it well.
|
|
||||||
<br clear="all">
|
|
||||||
:marked
|
|
||||||
Examples include:
|
|
||||||
* logging service
|
|
||||||
* data service
|
|
||||||
* message bus
|
|
||||||
* tax calculator
|
|
||||||
* application configuration
|
|
||||||
|
|
||||||
There is nothing specifically "Angular" about services. Angular itself has no definition of a "service".
|
|
||||||
There is no service base class, no place to register a "service".
|
|
||||||
|
|
||||||
Yet services are fundamental to any Angular application. Our components are big consumers of service.
|
|
||||||
|
|
||||||
We prefer our component classes lean. Our components don't fetch data from the server,
|
|
||||||
they don't validate user input, they don't log directly to console. They delegate such task to services.
|
|
||||||
|
|
||||||
A component's job is to enable the user experience and nothing more. It mediates between the view (rendered by the template)
|
|
||||||
and the application logic (which often includes some notion of a "model").
|
|
||||||
A good component presents properties and methods for data binding.
|
|
||||||
It delegates everything non-trivial to services.
|
|
||||||
|
|
||||||
Angular doesn't *enforce* these principles.
|
|
||||||
It won't complain if write a "kitchen sink" component with 3000 lines.
|
|
||||||
|
|
||||||
Angular does help us *follow* these principles ... by making it easy to factor our
|
|
||||||
application logic into services and make those services available to components through *dependency injection*.
|
|
||||||
|
|
||||||
.l-main-section
|
|
||||||
<a id="dependency-injection"></a>
|
|
||||||
:marked
|
|
||||||
## Dependency Injection
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/dependency-injection.png" alt="Service" style="float:left; width:200px; margin-left:-40px;margin-right:10px" )
|
|
||||||
:marked
|
|
||||||
"Dependency Injection" is a way to supply a new instance of a class
|
|
||||||
with the fully-formed dependencies it requires. Most dependencies are services.
|
|
||||||
Angular uses dependency injection to provide new components with the services they need.
|
|
||||||
<br clear="all">
|
|
||||||
:marked
|
|
||||||
In TypeScript, Angular can tell which services a component needs by looking at the types of its constructor parameters.
|
|
||||||
For example, the constructor of our `HeroListComponent` needs the `HeroService`:
|
|
||||||
+makeExample('intro/ts/src/app/hero-list.component.ts', 'ctor')
|
|
||||||
:marked
|
|
||||||
When Angular creates a component, it first asks an **Injector** for
|
|
||||||
the services that the component requires.
|
|
||||||
|
|
||||||
An `Injector` maintains a container of service instances that it has previously created.
|
|
||||||
If a requested service instance is not in the container, the injector makes one and adds it to the container
|
|
||||||
before returning the service to Angular.
|
|
||||||
When all requested services have been resolved and returned,
|
|
||||||
Angular can call the component's constructor with those services as arguments.
|
|
||||||
This is what we mean by *dependency injection*.
|
|
||||||
|
|
||||||
The process of `HeroService` injection looks a bit like this:
|
|
||||||
figure
|
|
||||||
img(src="/resources/images/devguide/intro/injector-injects.png" alt="Service" )
|
|
||||||
:marked
|
|
||||||
If the `Injector` doesn't have a `HeroService`, how does it know how to make one?
|
|
||||||
|
|
||||||
In brief, we must have previously registered a **provider** of the `HeroService` with the `Injector`.
|
|
||||||
A provider is something that can create or return a service, typically the service class itself.
|
|
||||||
|
|
||||||
We can register providers at any level of the application component tree.
|
|
||||||
We often do so at the root when we bootstrap the application so that
|
|
||||||
the same instance of a service is available everywhere.
|
|
||||||
+makeExample('intro/ts/src/app/boot.ts', 'bootstrap')
|
|
||||||
:marked
|
|
||||||
Alternatively, we might register at a component level ...
|
|
||||||
+makeExample('intro/ts/src/app/hero-list.component.ts', 'providers')
|
|
||||||
:marked
|
|
||||||
... in which case we get a new instance of the
|
|
||||||
service with each new instance of that component.
|
|
||||||
|
|
||||||
We've vastly over-simplified dependency injection for this overview.
|
|
||||||
We can learn the full story in the [Dependency Injection](dependency-injection.html) chapter.
|
|
||||||
|
|
||||||
The points to remember are:
|
|
||||||
* dependency injection is wired into the framework and used everywhere.<br><br>
|
|
||||||
* the `Injector` is the main mechanism.
|
|
||||||
* an injector maintains a *container* of service instances that it created.
|
|
||||||
* an injector can create a new service instance from a *provider*.
|
|
||||||
* a *provider* is a recipe for creating a service.
|
|
||||||
|
|
||||||
* we register *providers* with injectors.
|
## Other Resources
|
||||||
|
Don't neglect the other documentation resources.
|
||||||
<a id="other-stuff"></a>
|
|
||||||
.l-main-section
|
|
||||||
:marked
|
|
||||||
# The Other Stuff
|
|
||||||
|
|
||||||
We've learned just a bit about the seven main building blocks of an Angular application
|
The "[Cheat Sheet](cheatsheet.html)" is a handy map to Angular overall.
|
||||||
1. [Component](#component)
|
|
||||||
1. [Template](#template)
|
|
||||||
1. [Metadata](#metadata)
|
|
||||||
1. [Data Binding](#data-binding)
|
|
||||||
1. [Directive](#directive)
|
|
||||||
1. [Service](#service)
|
|
||||||
1. [Dependency Injection](#dependency-injection)
|
|
||||||
|
|
||||||
That's a foundation for everything else in an Angular application
|
The [API Guide](../api/) is the authority on every public-facing member of the Angular libraries.
|
||||||
and it's more than enough to get going.
|
|
||||||
But it doesn't include everything we'll need or want to know.
|
|
||||||
|
|
||||||
Below is a brief, alphabetical list of other important Angular features and services.
|
|
||||||
Most of them are covered in this Developers Guide (or soon will be):
|
|
||||||
|
|
||||||
>**Animations** - A forthcoming animation library makes it easy for developers to animate component behavior
|
|
||||||
without deep knowledge of animation techniques or css.
|
|
||||||
|
|
||||||
>**Bootstrap** - A method to configure and launch the root application component.
|
|
||||||
|
|
||||||
>**Change Detection** - Learn how Angular decides that a component property value has changed and
|
|
||||||
when to update the screen.
|
|
||||||
Learn how it uses **zones** to intercept asynchronous activity and run its change detection strategies.
|
|
||||||
|
|
||||||
>**Component Router** - With the Component Router service, users can navigate a multi-screen application
|
|
||||||
in a familiar web browsing style using URLs.
|
|
||||||
|
|
||||||
>**Events** - The DOM raise events. So can components and services. Angular offers mechanisms for
|
|
||||||
publishing and subscribing to events including an implementation of the [RxJS Observable](https://github.com/zenparsing/es-observable) proposal.
|
|
||||||
|
|
||||||
>**[Forms](forms.html)** - Support complex data entry scenarios with HTML-based validation and dirty checking.
|
|
||||||
|
|
||||||
>**HTTP** - Communicate with a server to get data, save data, and invoke server-side actions with this Angular HTTP client.
|
|
||||||
|
|
||||||
>**Lifecycle Hooks** - We can tap into key moments in the lifetime of a component, from its creation to its destruction,
|
|
||||||
by implementing the "Lifecycle Hook" interfaces.
|
|
||||||
|
|
||||||
>**[Pipes](pipes.html)** - Services that transform values for display.
|
|
||||||
We can put pipes in our templates to improve the user experience. For example,
|
|
||||||
this `currency` pipe expression,
|
|
||||||
<div style="margin-left:40px">
|
|
||||||
code-example(language="javascript" linenumbers=".").
|
|
||||||
price | currency:'USD':true'
|
|
||||||
</div>
|
|
||||||
:marked
|
|
||||||
>displays a price of "42.33" as `$42.33`.
|
|
||||||
|
|
||||||
>**[Testing](../testing/index.html)** - Angular provides a testing library for "unit testing" our application parts as they
|
|
||||||
interact with the Angular framework.
|
|
||||||
|
|
||||||
<a id="toh"></a>
|
<a id="toh"></a>
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
|
@ -520,7 +99,11 @@ figure.image-display
|
||||||
Fortunately, there are courageous heroes prepared to take on every challenge.
|
Fortunately, there are courageous heroes prepared to take on every challenge.
|
||||||
The shadowy "Hero Staffing Agency" matches crises to heroes.
|
The shadowy "Hero Staffing Agency" matches crises to heroes.
|
||||||
|
|
||||||
We are contract developers, hired by The Agency to build an application to manage their operations.
|
We are contract developers, hired by The Agency to build an Angular application to manage their operations.
|
||||||
The Agency maintains a stable of heroes with special powers.
|
The Agency maintains a stable of heroes with special powers.
|
||||||
We ordinary humans submit our crises as job requests. The heroes bid to take the job and The Agency
|
Ordinary humans call the agency, looking for help with their personal or global crises.
|
||||||
assigns each job accordingly. Our application handles every detail of recruiting, tracking and job assignment.
|
The Agency triages the crises and turns them into job requests.
|
||||||
|
The heroes on staff bid to take a job and The Agency
|
||||||
|
assigns each job accordingly.
|
||||||
|
|
||||||
|
Our application handles every detail of recruiting, tracking and job assignment.
|
||||||
|
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |