docs(architecture): move diagram up; elab on svcs; add LC Hooks links

This commit is contained in:
Ward Bell 2015-12-17 13:49:33 -08:00
parent f697e01b76
commit bf29846f3e
13 changed files with 585 additions and 480 deletions

View File

@ -2,11 +2,15 @@
import {Component} from 'angular2/core';
// #enddocregion import
import {HeroListComponent} from './hero-list.component';
import {SalesTaxComponent} from './sales-tax.component';
@Component({
selector: 'my-app',
template: '<hero-list></hero-list>',
directives: [HeroListComponent]
template: `
<hero-list></hero-list>
<sales-tax></sales-tax>
`,
directives: [HeroListComponent, SalesTaxComponent]
})
// #docregion export
export class AppComponent { }

View File

@ -1,18 +1,21 @@
import {Injectable} from 'angular2/core';
import {Injectable, Type} from 'angular2/core';
import {Logger} from './logger.service';
import {Hero} from './hero';
const HEROES = [
new Hero('Windstorm', 'Weather mastery'),
new Hero('Mr. Nice', 'Killing them with kindness'),
new Hero('Magneta', 'Manipulates metalic objects')
];
@Injectable()
export class BackendService {
constructor(private _logger: Logger) {}
getAll<T>(type: {new(...args:any[]): any }) : any[]{
getAll(type:Type) : PromiseLike<any[]>{
if (type === Hero) {
// TODO get from the database and return as a promise
return [
new Hero('Windstorm', 'Weather mastery'),
new Hero('Mr. Nice', 'Killing them with kindness'),
new Hero('Magneta', 'Manipulates metalic objects')];
// TODO get from the database
return Promise.resolve<Hero[]>(HEROES);
}
let err = new Error('Cannot get object of this type');
this._logger.error(err);

View File

@ -7,7 +7,5 @@ import {BackendService} from './backend.service';
import {Logger} from './logger.service';
// #docregion bootstrap
bootstrap(AppComponent, [
BackendService, HeroService, Logger
]);
bootstrap(AppComponent, [BackendService, HeroService, Logger]);
// #enddocregion bootstrap

View File

@ -1,9 +1,8 @@
// #docplaster
import {Component} from 'angular2/core';
import {Component, OnInit} from 'angular2/core';
import {Hero} from './hero';
import {HeroDetailComponent} from './hero-detail.component';
import {HeroService} from './hero.service'
import {HeroService} from './hero.service';
// #docregion metadata
// #docregion providers
@ -23,15 +22,18 @@ export class HeroesComponent { ... }
// #enddocregion metadata, providers
*/
// #docregion class
export class HeroListComponent {
export class HeroListComponent implements OnInit {
// #docregion ctor
constructor(service: HeroService) {
this.heroes = service.getHeroes();
}
constructor(private _service: HeroService){ }
// #enddocregion ctor
heroes:Hero[];
selectedHero: Hero;
ngOnInit(){
this.heroes = this._service.getHeroes();
}
selectHero(hero: Hero) { this.selectedHero = hero; }
}
// #enddocregion class

View File

@ -3,16 +3,23 @@ import {Hero} from './hero';
import {BackendService} from './backend.service';
import {Logger} from './logger.service';
// #docregion class
@Injectable()
// #docregion class
export class HeroService {
constructor(private _backend: BackendService, private _logger:Logger){}
// #docregion ctor
constructor(
private _backend: BackendService,
private _logger: Logger) { }
// #enddocregion ctor
private _heroes:Hero[] = [];
getHeroes() {
// TODO return as a promise
let heroes = <Hero[]> this._backend.getAll(Hero);
this._logger.log(`Got ${heroes.length} heroes from the server.`);
return heroes;
this._backend.getAll(Hero).then( (heroes:Hero[]) => {
this._logger.log(`Fetched ${heroes.length} heroes.`);
this._heroes.push(...heroes); // fill cache
});
return this._heroes;
}
}
// #enddocregion class

View File

@ -1,8 +1,11 @@
// #docregion
import {Injectable} from 'angular2/core';
@Injectable()
// #docregion class
export class Logger {
log(msg: any) { console.log(msg); }
error(msg: any) { console.error(msg); }
warn(msg: any) { console.warn(msg); }
}
// #enddocregion class

View File

@ -0,0 +1,41 @@
// #docplaster
// #docregion
import {Component} from 'angular2/core';
import {SalesTaxService} from './sales-tax.service';
import {TaxRateService} from './tax-rate.service';
// #docregion metadata
// #docregion providers
@Component({
// #enddocregion providers
selector: 'sales-tax',
template: `
<h2>Sales Tax Calculator</h2>
Amount: <input #amountBox (change)="0">
<div *ngIf=amountBox.value>
The sales tax is
{{ getTax(amountBox.value) | currency:'USD':true:'1.2-2' }}
</div>
`,
// #docregion providers
providers: [SalesTaxService, TaxRateService]
})
// #enddocregion providers
// #enddocregion metadata
/*
// #docregion metadata, providers
export class SalesTaxComponent { ... }
// #enddocregion metadata, providers
*/
// #docregion class
export class SalesTaxComponent {
// #docregion ctor
constructor(private _salesTaxService: SalesTaxService) { }
// #enddocregion ctor
getTax(value:string | number){
return this._salesTaxService.getVAT(value);
}
}
// #enddocregion class

View File

@ -0,0 +1,19 @@
// #docregion
import {Injectable, Inject} from 'angular2/core';
import {TaxRateService} from './tax-rate.service';
// #docregion class
@Injectable()
export class SalesTaxService {
constructor(private _rateService: TaxRateService) { }
getVAT(value:string | number){
let amount:number;
if (typeof value === "string"){
amount = parseFloat(value);
} else {
amount = value;
}
return (amount || 0) * this._rateService.getRate('VAT');
}
}
// #enddocregion class

View File

@ -0,0 +1,9 @@
// #docregion
import {Injectable} from 'angular2/core';
// #docregion class
@Injectable()
export class TaxRateService {
getRate(rateName:string){return 0.10;} // always 10% everywhere
}
// #enddocregion class

View File

@ -14,14 +14,13 @@ include ../../../../_includes/_util-fns
<!-- 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">
Of course there is more to it than this. We'll learn the details when we dive into the guide chapters.
Let's get the big picture first.
figure
img(src="/resources/images/devguide/architecture/overview2.png" alt="overview" style="margin-left:-40px;" width="700")
:marked
An Angular 2 application rests on eight main building blocks:
The architecture diagram identifies the eight main building blocks of an Angular 2 application:
1. [Module](#module)
1. [Component](#component)
1. [Template](#template)
@ -31,9 +30,6 @@ include ../../../../_includes/_util-fns
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
@ -53,6 +49,18 @@ figure
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>
.l-sub-section
:marked
### Modules are optional
We highly recommend modular design. TypeScript has great support for ES2015 module syntax and our chapters assume we're taking a modular
approach using that syntax. That's why we list *Module* among the basic building blocks.
Angular itself doesn't require a modular approach nor this particular syntax. Don't use it if you don't want it.
Each chapter has plenty to offer after you steer clear of the `import` and `export` statements.
Find setup and organization clues in the JavaScript track (select it from the combobox at the top of this page)
which demonstrates Angular 2 development with plain old JavaScript and no module system.
:marked
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
@ -144,7 +152,7 @@ figure
+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](#).
The developer can take action at each moment in this lifecycle through optional [Lifecycle Hooks](lifecycle-hooks.html).
.l-sub-section
:marked
We're not showing those hooks in this example
@ -233,7 +241,7 @@ code-example(language="html").
: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).
* `templateUrl` - the address of this component's template which we showed [above](#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`
@ -387,13 +395,23 @@ figure
* 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".
There is nothing specifically *Angular* about services. Angular itself has no definition of a *service*.
There is no *ServiceBase* class.
Yet services are fundamental to any Angular application. Our components are big consumers of services.
Yet services are fundamental to any Angular application.
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 the console. They delegate such tasks to services.
Here's an example of a service class that logs to the browser console
+makeExample('architecture/ts/app/logger.service.ts', 'class', 'app/logger.service.ts (class only)')(format=".")
:marked
Here's a `HeroServce` that fetches heroes and returns them in a resolved [promise](http://www.html5rocks.com/en/tutorials/es6/promises/).
The `HeroService` depends on the `LoggerService` and another `BackendService` that handles the server communication grunt work.
+makeExample('architecture/ts/app/hero.service.ts', 'class', 'app/hero.service.ts (class only)')(format=".")
:marked
Services are everywhere.
Our components are big consumers of services. They depend upon services to handle most chores.
They don't fetch data from the server, they don't validate user input, they don't log directly to the console.
They delegate such tasks 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
@ -499,7 +517,7 @@ figure
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
>**[Component Router](router.html)** - With the Component Router service, users can navigate a multi-screen application
in a familiar web browsing style using URLs.
>**Events** - The DOM raises events. So can components and services. Angular offers mechanisms for
@ -509,7 +527,7 @@ figure
>**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,
>**[Lifecycle Hooks](lifecycle-hooks.html)** - 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.

View File

@ -376,6 +376,7 @@
* `ngAfterViewChecked` - after every check of a component's view(s)
* `ngOnDestroy` - just before the directive is destroyed.
Learn more in the [Lifecycle Hooks](lifecycle-hooks.html) chapter.
.l-main-section
<a id="M"></a>
:marked

View File

@ -815,7 +815,7 @@ code-example(format="").
<a id="lifecycle-hooks"></a>
### Router Lifecycle Hooks
Angular components have their own lifecycle hooks. Angular calls the methods of the
Angular components have their own [lifecycle hooks](lifecycle-hooks.html). Angular calls the methods of the
[OnInit](../api/core/OnInit-interface.html) and [OnDestroy]((../api/core/OnDestroy-interface.html)
interfaces when it creates and destroys components.

View File

@ -126,7 +126,7 @@ figure.image-display
:marked
We also log when a component is created or destroyed
using the built-in `ngOnInit` and `ngOnDestroy` lifecycle hooks.
using the built-in `ngOnInit` and `ngOnDestroy` [lifecycle hooks](lifecycle-hooks.html).
Here it is in action:
figure.image-display