Merge remote-tracking branch 'origin/master'

# Conflicts:
#	public/docs/ts/latest/guide/style-guide.jade
#	public/docs/ts/latest/tutorial/toh-pt1.jade
#	public/docs/ts/latest/tutorial/toh-pt2.jade
#	public/docs/ts/latest/tutorial/toh-pt3.jade
#	public/docs/ts/latest/tutorial/toh-pt4.jade
#	public/docs/ts/latest/tutorial/toh-pt5.jade
This commit is contained in:
Zhicheng Wang 2016-06-14 14:04:30 +08:00
commit 7995cb4897
49 changed files with 634 additions and 561 deletions

4
.gitignore vendored
View File

@ -12,6 +12,7 @@ pubspec.lock
.DS_Store
**/*.iml
.idea
.vscode
**/js/latest/api
**/ts/latest/api
**/dart/latest/api
@ -21,8 +22,7 @@ _.*
public/docs/xref-*.*
_zip-output
www
npm-debug.log
npm-debug.log.*
npm-debug*.log*
*.plnkr.html
plnkr.html
*plnkr.no-link.html

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
5

View File

@ -10,6 +10,7 @@ env:
- DISPLAY=:99.0
- CHROME_BIN=chromium-browser
matrix:
- SCRIPT="lint"
- SCRIPT="run-e2e-tests --fast"
before_install:
- npm install -g gulp --no-optional

View File

@ -89,6 +89,18 @@ var _exampleProtractorBoilerplateFiles = [
'tsconfig.json'
];
var _exampleConfigFilename = 'example-config.json';
function isDartPath(path) {
// Testing via indexOf() for now. If we need to match only paths with folders
// named 'dart' vs 'dart*' then try: path.match('/dart(/|$)') != null;
return path.indexOf('/dart') > -1;
}
function excludeDartPaths(paths) {
return paths.filter(function (p) { return !isDartPath(p); });
}
/**
* Run Protractor End-to-End Specs for Doc Samples
* Alias for 'run-e2e-tests'
@ -165,7 +177,6 @@ function runE2e() {
// with the corresponding apps that they should run under. Then run
// each app/spec collection sequentially.
function findAndRunE2eTests(filter, outputFile) {
// create an output file with header.
var lang = (argv.lang || '(ts|js)').toLowerCase();
if (lang === 'all') { lang = '(ts|js|dart)'; }
@ -203,8 +214,7 @@ function findAndRunE2eTests(filter, outputFile) {
var status = { passed: [], failed: [] };
return examplePaths.reduce(function (promise, examplePath) {
return promise.then(function () {
var isDart = examplePath.indexOf('/dart') > -1;
var runTests = isDart ? runE2eDartTests : runE2eTsTests;
var runTests = isDartPath(examplePath) ? runE2eDartTests : runE2eTsTests;
return runTests(examplePath, outputFile).then(function(ok) {
var arr = ok ? status.passed : status.failed;
arr.push(examplePath);
@ -221,18 +231,19 @@ function findAndRunE2eTests(filter, outputFile) {
// fileName; then shut down the example. All protractor output is appended
// to the outputFile.
function runE2eTsTests(appDir, outputFile) {
// spawn tasks to start the app
var appBuildSpawnInfo;
var appRunSpawnInfo;
if (fs.existsSync(path.join(appDir, 'angular-cli.json'))) {
appBuildSpawnInfo = spawnExt('npm', ['run', 'build:cli'], { cwd: appDir });
appRunSpawnInfo = spawnExt('npm', ['run', 'http-server:cli', '--', '-s'], { cwd: appDir });
} else {
appBuildSpawnInfo = spawnExt('npm',['run','tsc'], { cwd: appDir });
appRunSpawnInfo = spawnExt('npm',['run','http-server:e2e', '--', '-s' ], { cwd: appDir });
// Grab protractor configuration or defaults to systemjs config.
try {
var exampleConfig = fs.readJsonSync(`${appDir}/${_exampleConfigFilename}`);
} catch (e) {
exampleConfig = {
build: 'tsc',
run: 'http-server:e2e'
};
}
var appBuildSpawnInfo = spawnExt('npm', ['run', exampleConfig.build], { cwd: appDir });
var appRunSpawnInfo = spawnExt('npm', ['run', exampleConfig.run, '--', '-s'], { cwd: appDir });
return runProtractor(appBuildSpawnInfo.promise, appDir, appRunSpawnInfo, outputFile);
}
@ -375,7 +386,7 @@ gulp.task('add-example-boilerplate', function() {
});
realPath = path.join(EXAMPLES_PATH, '/typings');
var typingsPaths = getTypingsPaths(EXAMPLES_PATH);
var typingsPaths = excludeDartPaths(getTypingsPaths(EXAMPLES_PATH));
typingsPaths.forEach(function(linkPath) {
gutil.log("symlinking " + linkPath + ' -> ' + realPath)
fsUtils.addSymlink(realPath, linkPath);
@ -398,16 +409,18 @@ function copyExampleBoilerplate() {
var sourceFiles = _exampleBoilerplateFiles.map(function(fn) {
return path.join(EXAMPLES_PATH, fn);
});
var examplePaths = getExamplePaths(EXAMPLES_PATH);
var examplePaths = excludeDartPaths(getExamplePaths(EXAMPLES_PATH));
var dartWebSourceFiles = _exampleDartWebBoilerPlateFiles.map(function(fn){
return path.join(EXAMPLES_PATH, fn);
});
var dartExampleWebPaths = getDartExampleWebPaths(EXAMPLES_PATH);
return copyFiles(sourceFiles, examplePaths)
// Make boilerplate files read-only to avoid that they be edited by mistake.
var destFileMode = '444';
return copyFiles(sourceFiles, examplePaths, destFileMode)
.then(function() {
return copyFiles(dartWebSourceFiles, dartExampleWebPaths);
return copyFiles(dartWebSourceFiles, dartExampleWebPaths, destFileMode);
})
// copy certain files from _examples/_protractor dir to each subdir that contains an e2e-spec file.
.then(function() {
@ -415,7 +428,7 @@ function copyExampleBoilerplate() {
_exampleProtractorBoilerplateFiles
.map(function(name) {return path.join(EXAMPLES_PROTRACTOR_PATH, name);});;
var e2eSpecPaths = getE2eSpecPaths(EXAMPLES_PATH);
return copyFiles(protractorSourceFiles, e2eSpecPaths);
return copyFiles(protractorSourceFiles, e2eSpecPaths, destFileMode);
});
}
@ -789,16 +802,23 @@ function showHideExampleNodeModules(showOrHide) {
}
}
// Copies fileNames into destPaths, setting the mode of the
// files at the destination as optional_destFileMode if given.
// returns a promise
function copyFiles(fileNames, destPaths) {
function copyFiles(fileNames, destPaths, optional_destFileMode) {
var copy = Q.denodeify(fsExtra.copy);
var chmod = Q.denodeify(fsExtra.chmod);
var copyPromises = [];
destPaths.forEach(function(destPath) {
fileNames.forEach(function(fileName) {
var baseName = path.basename(fileName);
var destName = path.join(destPath, baseName);
var p = copy(fileName, destName, { clobber: true});
if(optional_destFileMode !== undefined) {
p = p.then(function () {
return chmod(destName, optional_destFileMode);
});
}
copyPromises.push(p);
});
});
@ -841,7 +861,7 @@ function getTypingsPaths(basePath) {
function getExamplePaths(basePath, includeBase) {
// includeBase defaults to false
return getPaths(basePath, "example-config.json", includeBase)
return getPaths(basePath, _exampleConfigFilename, includeBase)
}
function getDartExampleWebPaths(basePath) {

View File

@ -235,7 +235,7 @@ script.
//- Returns truthy iff path is example project relative.
- var isProjRelDir = function(path) {
- return !path.match(/\/(js|ts|dart)(-snippets)?\//) && !path.endsWith('e2e-spec.js');
- return !path.match(/\/(js|ts|dart)(-snippets)?\//) && !path.endsWith('e2e-spec.ts');
- // Last conjunct handles case for shared project e2e test file like
- // cb-component-communication/e2e-spec.js (is shared between ts & dart)
- // TODO: generalize: compare start with getExampleName(); which needs to be fixed.

View File

@ -1,23 +1,17 @@
# _exampleBoilerplateFiles
.editorconfig
.idea
.vscode
styles.css
typings
typings.json
node_modules
jspm_packages
*.js.map
package.json
karma.conf.js
karma-test-shim.js
package.json
*/**/styles.css
systemjs.config.js
tsconfig.json
tslint.json
typings.json
wallaby.js
npm-debug*.
protractor.config.js
systemjs.config.js
_test-output
_temp
**/ts/**/*.js
**/ts-snippets/**/*.js
*.d.ts

View File

@ -36,3 +36,4 @@ Thumbs.db
!config/karma.conf.js
!config/protractor.conf.js
!src/typings.d.ts
!src/tsconfig.json

View File

@ -0,0 +1,4 @@
{
"build": "build:cli",
"run": "http-server:cli"
}

View File

@ -0,0 +1,22 @@
{
"compileOnSave": false,
"compilerOptions": {
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noImplicitAny": false,
"outDir": "../dist/",
"rootDir": ".",
"sourceMap": true,
"target": "es5",
"inlineSources": true
},
"files": [
"main.ts",
"typings.d.ts"
]
}

View File

@ -18,7 +18,7 @@
"webdriver:update": "webdriver-manager update",
"start:webpack": "webpack-dev-server --inline --progress --port 8080",
"test:webpack": "karma start karma.webpack.conf.js",
"build:webpack": "rimraf dist && webpack --config config/webpack.prod.js --progress --profile --bail",
"build:webpack": "rimraf dist && webpack --config config/webpack.prod.js --bail",
"build:cli": "ng build"
},
"keywords": [],

View File

@ -41,7 +41,7 @@
// Bundled (~40 requests):
function packUmd(pkgName) {
packages['@angular/'+pkgName] = { main: pkgName + '.umd.js', defaultExtension: 'js' };
};
}
// Most environments should use UMD; some (Karma) need the individual index files
var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
@ -52,7 +52,7 @@
var config = {
map: map,
packages: packages
}
};
System.config(config);

View File

@ -40,7 +40,7 @@
// Bundled (~40 requests):
function packUmd(pkgName) {
packages['@angular/'+pkgName] = { main: pkgName + '.umd.js', defaultExtension: 'js' };
};
}
// Most environments should use UMD; some (Karma) need the individual index files
var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
@ -51,7 +51,7 @@
var config = {
map: map,
packages: packages
}
};
System.config(config);

View File

@ -66,7 +66,7 @@
},
map: map,
packages: packages
}
};
System.config(config);

View File

@ -0,0 +1,26 @@
/// <reference path="../_protractor/e2e.d.ts" />
describe('Tutorial part 1', () => {
let expectedH1 = 'Tour of Heroes';
let expectedTitle = `Angular 2 ${expectedH1}`;
let hero = { id: 1, name: 'Windstorm' };
let expectedH2 = `${hero.name} details!`;
beforeEach(() => {
return browser.get('');
});
it(`should have title '${expectedTitle}'`, () => {
expect(browser.getTitle()).toEqual(expectedTitle);
});
it(`should have '${expectedH2}'`, () => {
let text = element(by.css('h2')).getText();
expect(text).toEqual(expectedH2);
});
it(`should have input name '${hero.name}'`, () => {
let name = element(by.css('input')).getAttribute('value');
expect(name).toEqual(hero.name);
});
});

View File

@ -37,10 +37,3 @@ export class AppComponent {
hero = 'Windstorm';
}
// #enddocregion app-component-1
// #docregion hero-property-1
hero: Hero = {
id: 1,
name: 'Windstorm'
};
// #enddocregion hero-property-1

View File

@ -22,10 +22,11 @@ export class Hero {
})
export class AppComponent {
title = 'Tour of Heroes';
// #docregion hero-property-1
hero: Hero = {
id: 1,
name: 'Windstorm'
};
// #enddocregion hero-property-1
}
// #enddocregion pt1

View File

@ -1,4 +1,4 @@
// #docregion pt2
// #docregion
import { Component } from '@angular/core';
export class Hero {
@ -42,7 +42,7 @@ const HEROES: Hero[] = [
</div>
</div>
`,
// #docregion styles-1
// #docregion styles
styles: [`
.selected {
background-color: #CFD8DC !important;
@ -92,18 +92,16 @@ const HEROES: Hero[] = [
border-radius: 4px 0 0 4px;
}
`]
// #enddocregion styles-1
// #enddocregion styles
})
export class AppComponent {
title = 'Tour of Heroes';
heroes = HEROES;
// #docregion selected-hero-1
// #docregion selected-hero
selectedHero: Hero;
// #enddocregion selected-hero-1
// #enddocregion selected-hero
// #docregion on-select-1
// #docregion on-select
onSelect(hero: Hero) { this.selectedHero = hero; }
// #enddocregion on-select-1
// #enddocregion on-select
}
// #enddocregion pt2

View File

@ -1,7 +1,5 @@
// #docregion pt1
import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
bootstrap(AppComponent);
// #enddocregion pt1

View File

@ -61,5 +61,3 @@ export class AppComponent implements OnInit {
onSelect(hero: Hero) { this.selectedHero = hero; }
// #docregion on-init
}
// #enddocregion on-init
// #enddocregion

View File

@ -6,7 +6,7 @@ import { Hero } from './hero';
selector: 'my-hero-detail',
template: `
<div *ngIf="hero">
<h2>{{hero.name}} details</h2>
<h2>{{hero.name}} details!</h2>
<div>
<label>id: </label>{{hero.id}}
</div>

View File

@ -6,18 +6,14 @@ import { Injectable } from '@angular/core';
// #enddocregion empty-class
import { HEROES } from './mock-heroes';
// #docregion empty-class
// #docregion getHeroes-stub
// #docregion empty-class, getHeroes-stub
@Injectable()
export class HeroService {
// #enddocregion empty-class
// #enddocregion empty-class
getHeroes() {
// #enddocregion getHeroes-stub
// #enddocregion getHeroes-stub
return HEROES;
// #docregion getHeroes-stub
// #docregion getHeroes-stub
}
// #docregion empty-class
// #docregion empty-class
}
// #enddocregion getHeroes-stub
// #enddocregion empty-class
// #enddocregion

View File

@ -12,8 +12,8 @@ export class HeroService {
getHeroes() {
return Promise.resolve(HEROES);
}
// #enddocregion get-heroes
// #enddocregion just-get-heroes
// #enddocregion get-heroes, just-get-heroes
// #enddocregion
// See the "Take it slow" appendix
// #docregion get-heroes-slowly
getHeroesSlowly() {
@ -22,7 +22,6 @@ export class HeroService {
);
}
// #enddocregion get-heroes-slowly
// #docregion
// #docregion just-get-heroes
}
// #enddocregion just-get-heroes
// #enddocregion

View File

@ -13,4 +13,3 @@ export var HEROES: Hero[] = [
{id: 19, name: 'Magma'},
{id: 20, name: 'Tornado'}
];
// #enddocregion

View File

@ -11,7 +11,6 @@ import { HeroesComponent } from './heroes.component';
import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from '@angular/router-deprecated';
// #docregion
@Component({
selector: 'my-app',
template: `
@ -20,13 +19,12 @@ import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from '@angular/route
`,
directives: [HeroesComponent],
providers: [
// #enddocregion
// #enddocregion
ROUTER_PROVIDERS,
// #docregion
// #docregion
HeroService
]
})
export class AppComponent {
title = 'Tour of Heroes';
}
// #enddocregion

View File

@ -10,14 +10,14 @@ import { HeroesComponent } from './heroes.component';
@Component({
selector: 'my-app',
// #docregion template
// #docregion template
template: `
<h1>{{title}}</h1>
<a [routerLink]="['Heroes']">Heroes</a>
<router-outlet></router-outlet>
`,
// #enddocregion template
// #docregion directives-and-providers
// #enddocregion template
// #docregion directives-and-providers
directives: [ROUTER_DIRECTIVES],
providers: [
ROUTER_PROVIDERS,
@ -37,4 +37,3 @@ import { HeroesComponent } from './heroes.component';
export class AppComponent {
title = 'Tour of Heroes';
}
// #enddocregion

View File

@ -1,5 +1,4 @@
/* #docplaster */
/* #docregion css */
/* #docregion */
h1 {
font-size: 1.2em;
color: #999;
@ -28,4 +27,3 @@ nav a:hover {
nav a.router-link-active {
color: #039be5;
}
/* #enddocregion css */

View File

@ -12,7 +12,7 @@ import { HeroService } from './hero.service';
@Component({
selector: 'my-app',
// #docregion template
// #docregion template
template: `
<h1>{{title}}</h1>
<nav>
@ -21,10 +21,10 @@ import { HeroService } from './hero.service';
</nav>
<router-outlet></router-outlet>
`,
// #enddocregion template
// #docregion style-urls
// #enddocregion template
// #docregion style-urls
styleUrls: ['app/app.component.css'],
// #enddocregion style-urls
// #enddocregion style-urls
directives: [ROUTER_DIRECTIVES],
providers: [
ROUTER_PROVIDERS,
@ -32,21 +32,21 @@ import { HeroService } from './hero.service';
]
})
@RouteConfig([
// #docregion dashboard-route
// #docregion dashboard-route
{
path: '/dashboard',
name: 'Dashboard',
component: DashboardComponent,
useAsDefault: true
},
// #enddocregion dashboard-route
// #docregion hero-detail-route
// #enddocregion dashboard-route
// #docregion hero-detail-route
{
path: '/detail/:id',
name: 'HeroDetail',
component: HeroDetailComponent
},
// #enddocregion hero-detail-route
// #enddocregion hero-detail-route
{
path: '/heroes',
name: 'Heroes',
@ -56,4 +56,3 @@ import { HeroService } from './hero.service';
export class AppComponent {
title = 'Tour of Heroes';
}
// #enddocregion

View File

@ -24,4 +24,3 @@ export class DashboardComponent implements OnInit {
gotoDetail() { /* not implemented yet */}
}
// #enddocregion component

View File

@ -1,4 +1,3 @@
/* #docplaster */
/* #docregion */
[class*='col-'] {
float: left;
@ -60,4 +59,3 @@ h4 {
min-width: 60px;
}
}
/* #enddocregion */

View File

@ -1,9 +1,9 @@
<!-- #docregion -->
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<!-- #docregion click -->
<!-- #docregion click -->
<div *ngFor="let hero of heroes" (click)="gotoDetail(hero)" class="col-1-4">
<!-- #enddocregion click -->
<!-- #enddocregion click -->
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>

View File

@ -22,12 +22,12 @@ export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
// #docregion ctor
// #docregion ctor
constructor(
private router: Router,
private heroService: HeroService) {
}
// #enddocregion ctor
// #enddocregion ctor
ngOnInit() {
this.heroService.getHeroes()
@ -41,4 +41,3 @@ export class DashboardComponent implements OnInit {
}
// #enddocregion goto-detail
}
// #enddocregion

View File

@ -1,7 +1,6 @@
// #docplaster
// #docregion
// #docregion v2
// #docregion import-oninit
// #docregion import-oninit, v2
import { Component, OnInit } from '@angular/core';
// #enddocregion import-oninit
// #docregion import-route-params
@ -18,25 +17,24 @@ import { HeroService } from './hero.service';
selector: 'my-hero-detail',
// #docregion template-url
templateUrl: 'app/hero-detail.component.html',
// #enddocregion template-url
// #enddocregion v2
// #enddocregion template-url, v2
styleUrls: ['app/hero-detail.component.css']
// #docregion v2
// #docregion v2
})
// #enddocregion extract-template
// #docregion implement
export class HeroDetailComponent implements OnInit {
// #enddocregion implement
// #enddocregion implement
hero: Hero;
// #docregion ctor
// #docregion ctor
constructor(
private heroService: HeroService,
private routeParams: RouteParams) {
}
// #enddocregion ctor
// #enddocregion ctor
// #docregion ng-oninit
// #docregion ng-oninit
ngOnInit() {
// #docregion get-id
let id = +this.routeParams.get('id');
@ -44,13 +42,11 @@ export class HeroDetailComponent implements OnInit {
this.heroService.getHero(id)
.then(hero => this.hero = hero);
}
// #enddocregion ng-oninit
// #enddocregion ng-oninit
// #docregion go-back
// #docregion go-back
goBack() {
window.history.back();
}
// #enddocregion go-back
}
// #enddocregion v2
// #enddocregion

View File

@ -24,4 +24,3 @@ export class HeroService {
}
// #enddocregion get-hero
}
// #enddocregion

View File

@ -17,5 +17,3 @@
</h2>
<button (click)="gotoDetail()">View Details</button>
</div>
<!-- #enddocregion mini-detail -->
<!-- #enddocregion -->

View File

@ -6,21 +6,18 @@ import { Router } from '@angular/router-deprecated';
import { Hero } from './hero';
import { HeroService } from './hero.service';
// #docregion metadata
// #docregion heroes-component-renaming
// #docregion heroes-component-renaming, metadata
@Component({
selector: 'my-heroes',
// #enddocregion heroes-component-renaming
// #enddocregion heroes-component-renaming
templateUrl: 'app/heroes.component.html',
styleUrls: ['app/heroes.component.css']
// #docregion heroes-component-renaming
// #docregion heroes-component-renaming
})
// #enddocregion heroes-component-renaming
// #enddocregion metadata
// #docregion class
// #docregion heroes-component-renaming
// #enddocregion heroes-component-renaming, metadata
// #docregion class, heroes-component-renaming
export class HeroesComponent implements OnInit {
// #enddocregion heroes-component-renaming
// #enddocregion heroes-component-renaming
heroes: Hero[];
selectedHero: Hero;
@ -41,8 +38,5 @@ export class HeroesComponent implements OnInit {
gotoDetail() {
this.router.navigate(['HeroDetail', { id: this.selectedHero.id }]);
}
// #docregion heroes-component-renaming
// #docregion heroes-component-renaming
}
// #enddocregion heroes-component-renaming
// #enddocregion class
// #enddocregion

View File

@ -13,4 +13,3 @@ export var HEROES: Hero[] = [
{id: 19, name: 'Magma'},
{id: 20, name: 'Tornado'}
];
// #enddocregion

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<!-- #docregion head -->
<!-- #docregion base-href -->
<!-- #docregion base-href -->
<head>
<base href="/">
<!-- #enddocregion base-href -->

View File

@ -1,5 +1,11 @@
/* #docregion */
h2 {
/* #docregion toh-excerpt */
/* Master Styles */
h1 {
color: #369;
font-family: Arial, Helvetica, sans-serif;
font-size: 250%;
}
h2, h3 {
color: #444;
font-family: Arial, Helvetica, sans-serif;
font-weight: lighter;
@ -11,23 +17,7 @@ body, input[text], button {
color: #888;
font-family: Cambria, Georgia;
}
button {
font-family: Arial;
background-color: #eee;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
cursor: hand;
}
button:hover {
background-color: #cfd8dc;
}
button:disabled {
background-color: #eee;
color: #aaa;
cursor: auto;
}
/* . . . */
/* everywhere else */
* {
font-family: Arial, Helvetica, sans-serif;

View File

@ -1,6 +1,8 @@
// #docplaster
// #docregion
// #docregion, variables-imports
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
// #enddocregion variables-imports
import { RouteParams } from '@angular/router-deprecated';
import { Hero } from './hero';
@ -11,11 +13,13 @@ import { HeroService } from './hero.service';
templateUrl: 'app/hero-detail.component.html',
styleUrls: ['app/hero-detail.component.css']
})
// #docregion variables-imports
export class HeroDetailComponent implements OnInit {
@Input() hero: Hero;
@Output() close = new EventEmitter();
error: any;
navigated = false; // true if navigated here
// #enddocregion variables-imports
constructor(
private heroService: HeroService,

View File

@ -0,0 +1,18 @@
/// <reference path="../_protractor/e2e.d.ts" />
describe('QuickStart E2E Tests', function () {
let expectedMsg = 'Hello from Angular 2 App with Webpack';
beforeEach(function () {
browser.get('');
});
it(`should display: ${expectedMsg}`, function () {
expect(element(by.css('h1')).getText()).toEqual(expectedMsg);
});
it('should display an image', function () {
expect(element(by.css('img')).isPresent()).toBe(true);
});
});

View File

@ -0,0 +1,4 @@
{
"build": "build:webpack",
"run": "http-server:cli"
}

View File

@ -126,11 +126,10 @@ a(id='toc')
我们遵循[单一职责原则](https:\/\/en.wikipedia.org/wiki/Single_responsibility_principle)来创建的所有组件、服务和其它标志等。这样能帮助我们把应用程序弄的干净整洁,易于阅读、维护和测试。
### Rule of One
### 单一法则
<a id="01-01"></a>
#### Style 01-01
#### 风格 01-01
### <a id="01-01"></a>Rule of One
### <a id="01-01"></a>单一法则
#### <a href="#01-01">Style 01-01</a>
#### <a href="#01-01">风格 01-01</a>
.s-rule.do
:marked
**Do** define one thing (e.g. service or component) per file.
@ -202,12 +201,13 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Small Functions
### 小函数
<a id="01-02"></a>
#### Style 01-02
#### 风格01-02
.s-rule.do
### <a id="01-02"></a>Small Functions
### <a id="01-02"></a>小函数
#### <a href="#01-02">Style 01-02</a>
#### <a href="#01-02">风格01-02</a>
:marked
**Do** define small functions
@ -263,11 +263,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### General Naming Guidelines
### 总体命名指导原则
<a id="02-01"></a>
#### Style 02-01
#### 风格02-01
### <a id="02-01"></a>General Naming Guidelines
### <a id="02-01"></a>总体命名知道原则
#### <a href="#02-01">Style 02-01</a>
#### <a href="#02-01">风格02-01</a>
.s-rule.do
:marked
@ -307,11 +306,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Separate File Names with Dots and Dashes
### 使用点和横杠来分隔文件名字
<a id="02-02"></a>
#### Style 02-02
#### 风格02-02
### <a id="02-02"></a>Separate File Names with Dots and Dashes
### <a id="02-02"></a>使用点和横杠来分隔文件名
#### <a href="#02-02">Style 02-02</a>
#### <a href="#02-02">风格02-02</a>
.s-rule.do
:marked
@ -376,11 +374,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Components and Directives
### 组件和指令命名
<a id="02-03"></a>
#### Style 02-03
#### 风格02-03
### <a id="02-03"></a>Components and Directives
### <a id="02-03"></a>组件与指令命名
#### <a href="#02-03">Style 02-03</a>
#### <a href="#02-03">风格02-03</a>
.s-rule.do
:marked
@ -478,11 +475,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Service Names
### 服务名
<a id="02-04"></a>
#### Style 02-04
#### 风格02-04
### <a id="02-04"></a>Service Names
### <a id="02-04"></a>服务名
#### <a href="#02-04">Style 02-04</a>
#### <a href="#02-04">风格02-04</a>
.s-rule.do
:marked
@ -563,11 +559,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Bootstrapping
### 引导程序
<a id="02-05"></a>
#### Style 02-05
#### 风格02-05
### <a id="02-05"></a>Bootstrapping
### <a id="02-05"></a>引导
#### <a href="#02-05">Style 02-05</a>
#### <a href="#02-05">风格02-05</a>
.s-rule.do
:marked
@ -600,11 +595,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Directive Selectors
### 指令的选择器
<a id="02-06"></a>
#### Style 02-06
#### 风格02-06
### <a id="02-06"></a>Directive Selectors
### <a id="02-06"></a>指令的选择器
#### <a href="#02-06">Style 02-06</a>
#### <a href="#02-06">风格02-06</a>
.s-rule.do
:marked
@ -631,11 +625,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Custom Prefix for Components
### 为组件自定义前缀
<a id="02-07"></a>
#### Style 02-07
#### 风格02-07
### <a id="02-07"></a>Custom Prefix for Components
### <a id="02-07"></a>为组件自定义前缀
#### <a href="#02-07">Style 02-07</a>
#### <a href="#02-07">风格02-07</a>
.s-rule.do
:marked
@ -680,11 +673,10 @@ a(href="#toc") 回到顶部
:marked
:marked
### Custom Prefix for Directives
### 为指令添加自定义前缀
<a id="02-08"></a>
#### Style 02-08
#### 风格02-08
### <a id="02-08"></a>Custom Prefix for Directives
### <a id="02-08"></a>为指令添加自定义前缀
#### <a href="#02-08">Style 02-08</a>
#### <a href="#02-08">风格02-08</a>
.s-rule.do
:marked
@ -716,11 +708,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Pipe Names
### 管道名
<a id="02-09"></a>
#### Style 02-09
#### 风格02-09
### <a id="02-09"></a>Pipe Names
### <a id="02-09"></a>管道名
#### <a href="#02-09">Style 02-09</a>
#### <a href="#02-09">风格02-09</a>
.s-rule.do
:marked
@ -769,11 +760,9 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Unit Test File Names
### 单元测试文件命名
<a id="02-10"></a>
#### Style 02-10
#### 风格02-10
### <a id="02-10"></a>Unit Test File Names
### <a id="02-10"></a>单元测试文件名
#### <a href="#02-10">风格02-10</a>
.s-rule.do
:marked
@ -856,11 +845,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### End to End Test File Names
### 端到端测试文件命名
<a id="02-11"></a>
#### Style 02-11
#### 风格02-11
### <a id="02-11"></a>End to End Test File Names
### <a id="02-11"></a>端到端测试文件名
#### <a href="#02-11">Style 02-11</a>
#### <a href="#02-11">风格02-11</a>
.s-rule.do
:marked
@ -921,11 +909,8 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Classes
### 类
<a id="03-01"></a>
#### Style 03-01
#### 风格03-01
### <a id="03-01"></a>类
#### <a href="#03-01">风格03-01</a>
.s-rule.do
:marked
@ -958,11 +943,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Constants
### 常量
<a id="03-02"></a>
#### Style 03-02
#### 风格03-02
### <a id="03-02"></a>Constants
### <a id="03-02"></a>常量
#### <a href="#03-02">Style 03-02</a>
#### <a href="#03-02">风格03-02</a>
.s-rule.do
:marked
@ -995,11 +979,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Interfaces
### 接口
<a id="03-03"></a>
#### Style 03-03
#### 风格03-03
### <a id="03-03"></a>Interfaces
### <a id="03-03"></a>接口
#### <a href="#03-03">Style 03-03</a>
#### <a href="#03-03">风格03-03</a>
.s-rule.do
:marked
@ -1032,11 +1015,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Properties and Methods
### 属性和方法名
<a id="03-04"></a>
#### Style 03-04
#### 风格03-04
### <a id="03-04"></a>Properties and Methods
### <a id="03-04"></a>属性和方法
#### <a href="#03-04">Style 03-04</a>
#### <a href="#03-04">样式03-04</a>
.s-rule.do
:marked
@ -1081,11 +1063,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Import Destructuring Spacing
### 导入语句解构表达式中的空格
<a id="03-05"></a>
#### Style 03-05
#### 风格03-05
### <a id="03-05"></a>Import Destructuring Spacing
### <a id="03-05"></a>导入语句解构表达式中的空格
#### <a href="#03-05">Style 03-05</a>
#### <a href="#03-05">风格03-05</a>
.s-rule.do
:marked
@ -1111,11 +1092,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Import Line Spacing
### 导入语句中的空行
<a id="03-06"></a>
#### Style 03-06
#### 风格03-06
### <a id="03-06"></a>Import Line Spacing
### <a id="03-06"></a>导入语句中的空行
#### <a href="#03-06">Style 03-06</a>
#### <a href="#03-06">风格03-06</a>
.s-rule.do
:marked
@ -1179,11 +1159,9 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### LIFT
### LIFT (定位`L`ocate、识别`I`dentity、平面化`F`lattest、尝试`T`ry遵循不重复自己DRY - Do Not Repeat Yourself约定)
<a id="04-01"></a>
#### Style 04-01
#### 风格04-01
### <a id="04-01"></a>LIFT
#### <a href="#04-01">Style 04-01</a>
#### <a href="#04-01">风格04-01</a>
.s-rule.do
:marked
@ -1208,11 +1186,11 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Locate
### 定位
<a id="04-02"></a>
#### Style 04-02
#### 风格04-02
### <a id="04-02"></a>Locate
### <a id="04-02"></a>定位
#### <a href="#04-02">Style 04-02</a>
#### <a href="#04-02">风格04-02</a>
.s-rule.do
:marked
@ -1232,11 +1210,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Identify
### 识别
<a id="04-03"></a>
#### Style 04-03
#### 风格04-03
### <a id="04-03"></a>Identify
### <a id="04-03"></a>识别
#### <a href="#04-03">Style 04-03</a>
#### <a href="#04-03">风格04-03</a>
.s-rule.do
:marked
@ -1275,11 +1252,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Flat
### 平面化
<a id="04-04"></a>
#### Style 04-04
#### 风格04-04
### <a id="04-04"></a>Flat
### <a id="04-04"></a>平面化
#### <a href="#04-04">Style 04-04</a>
#### <a href="#04-04">风格04-04</a>
.s-rule.do
:marked
@ -1305,11 +1281,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### T-DRY (Try to be DRY)
### T-DRY(尝试遵循不重复自己DRY的约定)
<a id="04-05"></a>
#### Style 04-05
#### 风格04-05
### <a id="04-05"></a>T-DRY (Try to be DRY)
### <a id="04-05"></a>T-DRY (尝试遵循不重复自己DRY的约定)
#### <a href="#04-05">Style 04-05</a>
#### <a href="#04-05">风格04-05</a>
.s-rule.do
:marked
@ -1335,11 +1310,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Overall Structural Guidelines
### 总体结构指导原则
<a id="04-06"></a>
#### Style 04-06
#### 风格04-06
### <a id="04-06"></a>Overall Structural Guidelines
### <a id="04-06"></a>总体结构指导原则
#### <a href="#04-06">Style 04-06</a>
#### <a href="#04-06">风格04-06</a>
.s-rule.do
:marked
@ -1422,11 +1396,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Shared Folder
### 共享目录
<a id="04-07"></a>
#### Style 04-07
#### 风格04-07
### <a id="04-07"></a>Shared Folder
### <a id="04-07"></a>共享目录
#### <a href="#04-07">Style 04-07</a>
#### <a href="#04-07">风格04-07</a>
.s-rule.do
:marked
@ -1495,11 +1468,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Folders-by-Feature Structure
### 根据特性划分的目录结构
<a id="04-08"></a>
#### Style 04-08
#### 风格04-08
### <a id="04-08"></a>Folders-by-Feature Structure
### <a id="04-08"></a>根据特性划分的目录结构
#### <a href="#04-08">Style 04-08</a>
#### <a href="#04-08">风格04-08</a>
.s-rule.do
:marked
@ -1586,11 +1558,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Layout Components
### 布局组件
<a id="04-09"></a>
#### Style 04-09
#### 风格04-09
### <a id="04-09"></a>Layout Components
### <a id="04-09"></a>布局组件
#### <a href="#04-09">Style 04-09</a>
#### <a href="#04-09">风格04-09</a>
.s-rule.do
:marked
@ -1650,11 +1621,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Create and Import Barrels
### 新建和导入封装桶
<a id="04-10"></a>
#### Style 04-10
#### 风格04-10
### <a id="04-10"></a>Create and Import Barrels
### <a id="04-10"></a>创建和导入封装桶
#### <a href="#04-10">Style 04-10</a>
#### <a href="#04-10">风格04-10</a>
.s-rule.consider
:marked
@ -1760,11 +1730,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Lazy Loaded Folders
### 惰性加载目录
<a id="04-11"></a>
#### Style 04-11
#### 风格04-11
### <a id="04-11"></a>Lazy Loaded Folders
### <a id="04-11"></a>惰性加载目录
#### <a href="#04-11">Style 04-11</a>
#### <a href="#04-11">风格04-11</a>
A distinct application feature or workflow may be *lazy loaded* or *loaded on demand* rather than when the application starts.
一个独特的应用程序特性或者工作流可能被**惰性加载**或**按需加载**,而非在应用程序启动时就全部加载。
@ -1788,11 +1757,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Prefix Lazy Loaded Folders with +
### 为惰性加载目录名字加前缀+
<a id="04-12"></a>
#### Style 04-12
#### 风格04-12
### <a id="04-12"></a>Prefix Lazy Loaded Folders with +
### <a id="04-12"></a>为惰性加载目录名字加前缀+
#### <a href="#04-12">Style 04-12</a>
#### <a href="#04-12">样式04-12</a>
.s-rule.do
:marked
@ -1836,11 +1804,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Never Directly Import Lazy Loaded Folders
### 决不直接导入惰性加载目录
<a id="04-13"></a>
#### Style 04-13
#### 风格
### <a id="04-13"></a>Never Directly Import Lazy Loaded Folders
### <a id="04-13"></a>决不直接导入惰性加载目录
#### <a href="#04-13">Style 04-13</a>
#### <a href="#04-13">风格04-13</a>
.s-rule.avoid
:marked
@ -1863,11 +1830,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Lazy Loaded Folders May Import From a Parent
### <a id="04-14"></a>Lazy Loaded Folders May Import From a Parent
### 惰性加载目录可以导入父级
<a id="04-14"></a>
#### Style 04-14
#### 风格04-14
#### <a href="#04-14">Style 04-14</a>
#### <a href="#04-14">样式04-14</a>
.s-rule.do
:marked
@ -1891,11 +1857,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Use Component Router to Lazy Load
### 使用组件路由器来惰性加载
<a id="04-15"></a>
#### Style 04-15
#### 风格04-15
### <a id="04-15"></a>Use Component Router to Lazy Load
### <a id="04-15"></a>使用组件路由器来惰性加载
#### <a href="#04-15">Style 04-15</a>
#### <a href="#04-15">风格04-15</a>
.s-rule.do
:marked
@ -1917,12 +1882,11 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
## Components
## 组件
### Components Selector Naming
### 组件选择器命名
<a id="05-02"></a>
#### Style 05-02
#### 风格05-02
### <a id="05-02"></a>Components Selector Naming
### <a id="05-02"></a>组件选择器命名
#### <a href="#05-02">Style 05-02</a>
#### <a href="#05-02">风格05-02</a>
.s-rule.do
:marked
@ -1953,11 +1917,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Components as Elements
### 将组件当做元素
<a id="05-03"></a>
#### Style 05-03
#### 风格05-03
### <a id="05-03"></a>Components as Elements
### <a id="05-03"></a>把组件当做元素
#### <a href="#05-03">Style 05-03</a>
#### <a href="#05-03">风格05-03</a>
.s-rule.do
:marked
@ -2003,11 +1966,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Extract Template and Styles to Their Own Files
### 把模板和样式提取到它们自己的文件
<a id="05-04"></a>
#### Style 05-04
#### 风格05-04
### <a id="05-04"></a>Extract Template and Styles to Their Own Files
### <a id="05-04"></a>把模板和样式提取到它们自己的文件
#### <a href="#05-04">Style 05-04</a>
#### <a href="#05-04">风格05-04</a>
.s-rule.do
:marked
@ -2059,11 +2021,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Decorate Input and Output Properties Inline
### 内联Input和Output属性装饰
<a id="05-12"></a>
#### Style 05-12
#### 风格05-12
### <a id="05-12"></a>Decorate Input and Output Properties Inline
### <a id="05-12"></a>内联Input和Output属性装饰器
#### <a href="#05-12">Style 05-12</a>
#### <a href="#05-12">风格05-12</a>
.s-rule.do
:marked
@ -2113,11 +2074,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Avoid Renaming Inputs and Outputs
### 避免重命名输入和输出
<a id="05-13"></a>
#### Style 05-13
#### 风格05-13
### <a id="05-13"></a>Avoid Renaming Inputs and Outputs
### <a id="05-13"></a>避免重命名输入和输出
#### <a href="#05-13">Style 05-13</a>
#### <a href="#05-13">风格05-13</a>
.s-rule.avoid
:marked
@ -2152,11 +2112,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Member Sequence
### 成员顺序
<a id="05-14"></a>
#### Style 05-14
#### 风格05-14
### <a id="05-14"></a>Member Sequence
### <a id="05-14"></a>成员顺序
#### <a href="#05-14">Style 05-14</a>
#### <a href="#05-14">风格05-14</a>
.s-rule.do
:marked
@ -2188,11 +2147,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Put Logic in Services
### 把逻辑放到服务里
<a id="05-15"></a>
#### Style 05-15
#### 风格05-15
### <a id="05-15"></a>Put Logic in Services
### <a id="05-15"></a>把逻辑放到服务里
#### <a href="#05-14">Style 05-15</a>
#### <a href="#05-14">风格05-15</a>
.s-rule.do
:marked
@ -2243,11 +2201,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Don't Prefix Output Properties
### 不要给输出属性加前缀
<a id="05-16"></a>
#### Style 05-16
#### 风格05-16
### <a id="05-16"></a>Don't Prefix Output Properties
### <a id="05-16"></a>不要给输出属性加前缀
#### <a href="#05-16">Style 05-16</a>
#### <a href="#05-16">风格05-16</a>
.s-rule.do
:marked
@ -2293,11 +2250,9 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Put Presentation Logic in the Component Class
### 把展示逻辑放到组件类里
<a id="05-17"></a>
#### Style 05-17
#### 风格05-17
### <a id="05-17"></a>把展示逻辑放到组件类里
#### <a href="#05-17">Style 05-17</a>
#### <a href="#05-17">风格05-17</a>
.s-rule.do
:marked
@ -2339,11 +2294,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Use Directives to Enhance an Existing Element
### 使用指令来加强已有元素
<a id="06-01"></a>
#### Style 06-01
#### 风格06-01
### <a id="06-01"></a>Use Directives to Enhance an Existing Element
### <a id="06-01"></a>使用指令来加强已有元素
#### <a href="#06-01">Style 06-01</a>
#### <a href="#06-01">风格06-01</a>
.s-rule.do
:marked
@ -2375,11 +2329,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Use HostListener and HostBinding Class Decorators
### 使用HostListener和HostBinding类装饰器
<a id="06-03"></a>
#### Style 06-03
#### 风格06-03
### <a id="06-03"></a>Use HostListener and HostBinding Class Decorators
### <a id="06-03"></a>使用HostListener和HostBinding类装饰器
#### <a href="#06-03">Style 06-03</a>
#### <a href="#06-03">风格06-03</a>
.s-rule.do
:marked
@ -2414,11 +2367,10 @@ a(href="#toc") 回到顶部
## Services
## 服务
### Services are Singletons in Same Injector
### 在同一个注入器内,服务是单例
<a id="07-01"></a>
#### Style 07-01
#### 风格07-01
### <a id="07-01"></a>Services are Singletons in Same Injector
### <a id="07-01"></a>在同一个注入器内,服务是单例
#### <a href="#07-01">Style 07-01</a>
#### <a href="#07-01">风格07-01</a>
.s-rule.do
:marked
@ -2447,11 +2399,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Single Responsibility
### 单一职责
<a id="07-02"></a>
#### Style 07-02
#### 风格07-02
### <a id="07-02"></a>Single Responsibility
### <a id="07-02"></a>单一职责
#### <a href="#07-02">Style 07-02</a>
#### <a href="#07-02">风格07-02</a>
.s-rule.do
:marked
@ -2483,11 +2434,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Providing a Service
### 服务的提供
<a id="07-03"></a>
#### Style 07-03
#### 风格07-03
### <a id="07-03"></a>Providing a Service
### <a id="07-03"></a>提供一个服务
#### <a href="#07-03">Style 07-03</a>
#### <a href="#07-03">风格07-03</a>
.s-rule.do
:marked
@ -2532,11 +2482,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Use the @Injectable() Class Decorator
### 使用@Injectable()类装饰器
<a id="07-04"></a>
#### Style 07-04
#### 风格07-04
### <a id="07-04"></a>Use the @Injectable() Class Decorator
### <a id="07-04"></a>使用@Injectable()类装饰器
#### <a href="#07-04">Style 07-04</a>
#### <a href="#07-04">风格07-04</a>
.s-rule.do
:marked
@ -2571,11 +2520,10 @@ a(href="#toc") 回到顶部
## Data Services
## 数据服务
### Separate Data Calls
### 分离数据调用
<a id="08-01"></a>
#### Style 08-01
#### 风格08-01
### <a id="08-01"></a>Separate Data Calls
### <a id="08-01"></a>分离数据调用
#### <a href="#08-01">Style 08-01</a>
#### <a href="#08-01">风格08-01</a>
.s-rule.do
:marked
@ -2625,11 +2573,10 @@ a(href="#toc") Back to top
.l-main-section
:marked
### Implement Lifecycle Hooks Interfaces
### 实现生命周期钩子的接口
<a id="09-01"></a>
#### Style 09-01
#### 风格09-01
### <a id="09-01"></a>Implement Lifecycle Hooks Interfaces
### <a id="09-01"></a>实现生命周期钩子接口
#### <a href="#09-01">Style 09-01</a>
#### <a href="#09-01">风格09-01</a>
.s-rule.do
:marked
@ -2667,11 +2614,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Component Router
### 组件路由器
<a id="10-01"></a>
#### Style 10-01
#### 风格10-01
### <a id="10-01"></a>Component Router
### <a id="10-01"></a>组件路由器
#### <a href="#10-01">Style 10-01</a>
#### <a href="#10-01">风格10-01</a>
.s-rule.do
:marked
@ -2731,11 +2677,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### Codelyzer
### Codelyzer
<a id="A-01"></a>
#### Style A-01
#### 风格A-01
### <a id="A-01"></a>Codelyzer
### <a id="A-01"></a>Codelyzer
#### <a href="#A-01">Style A-01</a>
#### <a href="#A-01">风格A-01</a>
.s-rule.do
:marked
@ -2755,11 +2700,10 @@ a(href="#toc") 回到顶部
.l-main-section
:marked
### File Templates and Snippets
### 文件模板和代码片段
<a id="A-02"></a>
#### Style A-02
#### 风格A-02
### <a id="A-02"></a>File Templates and Snippets
### <a id="A-02"></a>文档模板和代码片段
#### <a href="#A-02">Style A-02</a>
#### <a href="#A-02">风格A-02</a>
.s-rule.do
:marked

View File

@ -117,7 +117,7 @@ code-example(language="bash").
现在,有了一个`Hero`类,我们就要把组件`hero`属性的类型换成`Hero`了。
然后以`1`为id、以“Windstorm”为名字初始化它。
+makeExample('toh-1/ts-snippets/app.component.snippets.pt1.ts', 'hero-property-1', 'app.component.ts (hero属性)')(format=".")
+makeExample('toh-1/ts/app/app.component.ts', 'hero-property-1', 'app.component.ts (hero property)')(format=".")
:marked
Because we changed the hero from a string to an object,

View File

@ -71,7 +71,7 @@ code-example(language="bash").
我们先在`app.component.ts`的底部创建一个由十位英雄组成的数组。
+makeExample('toh-2/ts/app/app.component.ts', 'hero-array', 'app.component.ts (英雄数组)')
+makeExample('toh-2/ts/app/app.component.ts', 'hero-array', 'app.component.ts (hero array)')
:marked
The `HEROES` array is of type `Hero`, the class defined in part one,
@ -84,11 +84,11 @@ code-example(language="bash").
### Exposing heroes
### 导出英雄们
Lets create a property in `AppComponent` that exposes the heroes for binding.
Lets create a public property in `AppComponent` that exposes the heroes for binding.
我们在`AppComponent`上创建一个属性,用来暴露这些英雄,以供绑定。
我们在`AppComponent`上创建一个公开属性,用来暴露这些英雄,以供绑定。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'hero-array-1', 'app.component.ts (英雄数组属性)')
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'hero-array-1', 'app.component.ts (hero array property)')
:marked
We did not have to define the `heroes` type. TypeScript can infer it from the `HEROES` array.
@ -113,7 +113,7 @@ code-example(language="bash").
我们的组件有了`heroes`属性,我们再到模板中创建一个无序列表来显示他们。
我们将在标题和英雄详情之间插入下面这段HTML代码。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'heroes-template-1', 'app.component.ts (英雄模板)')
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'heroes-template-1', 'app.component.ts (heroes template)')
:marked
Now we have a template that we can fill with our heroes.
@ -160,7 +160,7 @@ code-example(language="bash").
引号中赋值给`ngFor`的那段儿文本表示“*从`heroes`数组中取出每个英雄,存入一个局部的`hero`变量,并让它在相应的模板实例中可用*”。
The `let` keyword before "hero" identifies the `hero` as a template input variable.
The `let` keyword before "hero" identifies `hero` as a template input variable.
We can reference this variable within the template to access a heros properties.
`hero`前的`let`关键字表示`hero`是一个模板输入变量。
@ -199,13 +199,16 @@ code-example(language="bash").
要想给我们的组件添加一些样式,请把`@Component`装饰器的`styles`属性设置为下列CSS类
+makeExample('toh-2/ts/app/app.component.ts', 'styles-1', 'app.component.ts (添加样式)')
+makeExample('toh-2/ts/app/app.component.ts', 'styles', 'app.component.ts (styles)')(format=".")
:marked
Notice that we again use the back-tick notation for multi-line strings.
注意,我们又使用了反引号语法来书写多行字符串。
That's a lot of styles! We can put them inline as shown here, or we can move them out to their own file which will make it easier to code our component.
We'll do this in a later chapter. For now let's keep rolling.
When we assign styles to a component they are scoped to that specific component.
Our styles will only apply to our `AppComponent` and won't "leak" to the outer HTML.
@ -216,14 +219,7 @@ code-example(language="bash").
用于显示英雄们的这个模板看起来像这样:
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'heroes-styled', 'app.component.ts (带样式的英雄们)')
:marked
That's a lot of styles! We can put them inline as shown here, or we can move them out to their own file which will make it easier to code our component.
We'll do this in a later chapter. For now let's keep rolling.
样式有很多种写法!我们可以像这里一样内联在代码中,也可以把它们移出去,放到各自的文件中,以便给组件编码时更容易。
等到后面的章节中我们肯定会这么干,但现在,还是保持现在的节奏吧。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'heroes-styled', 'app.component.ts (styled heroes)')
.l-main-section
:marked
@ -251,7 +247,7 @@ code-example(language="bash").
我们往`<li>`元素上插入一句Angular事件绑定代码绑定到它的click事件。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'selectedHero-click', 'app.component.ts (捕获click事件)')
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'selectedHero-click', 'app.component.ts (template excerpt)')
:marked
Focus on the event binding
@ -305,7 +301,7 @@ code-example(language="bash").
在`AppComponent`上,我们不再需要一个固定的`hero`属性。
那就直接把它改为`selectedHero`属性。
+makeExample('toh-2/ts/app/app.component.ts', 'selected-hero-1', 'app.component.ts (selectedHero)')
+makeExample('toh-2/ts/app/app.component.ts', 'selected-hero', 'app.component.ts (selectedHero)')
:marked
Weve decided that none of the heroes should be selected before the user picks a hero so
@ -316,7 +312,8 @@ code-example(language="bash").
Now **add an `onSelect` method** that sets the `selectedHero` property to the `hero` the user clicked.
现在,**添加一个`onSelect`方法**,以便在用户点击一个英雄的时候,把它赋给`selectedHero`属性。
+makeExample('toh-2/ts/app/app.component.ts', 'on-select-1', 'app.component.ts (onSelect)')
+makeExample('toh-2/ts/app/app.component.ts', 'on-select', 'app.component.ts (onSelect)')
:marked
We will be showing the selected hero's details in our template.
@ -326,7 +323,7 @@ code-example(language="bash").
我们将把所选英雄的详细信息显示在模板中。目前,它仍然引用的是以前的`hero`属性。
我们这就修改模板,让它绑定到新的`selectedHero`属性上去。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'selectedHero-details', 'app.component.ts (绑定到selectedHero的名字)')
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'selectedHero-details', 'app.component.ts (template excerpt)')
:marked
### Hide the empty detail with ngIf
### 利用ngIf隐藏空的详情
@ -428,19 +425,20 @@ code-example(language="bash").
关键是CSS类的名字`selected`。当两位英雄一致时,它为`true`,否则为`false`。
也就是说:“*当两位英雄匹配时,应用上`selected`类,否则不应用*”。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'class-selected-1', 'app.component.ts (设置CSS类)')(format=".")
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'class-selected-1', 'app.component.ts (setting the CSS class)')(format=".")
:marked
Notice in the template that the `class.selected` is surrounded in square brackets (`[]`).
This is the syntax for a Property Binding, a binding in which data flows one way
This is the syntax for a **property binding**, a binding in which data flows one way
from the data source (the expression `hero === selectedHero`) to a property of `class`.
注意,模板中的`class.selected`是括在一对方括号中的。
这就是“属性绑定”的语法,一种从数据源(即`hero === selectedHero`表达式)到`class`属性的单向数据流。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'class-selected-2', 'app.component.ts (Styling each hero)')(format=".")
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'class-selected-2', 'app.component.ts (styling each hero)')(format=".")
.l-sub-section
:marked
Learn more about [Property Binding](../guide/template-syntax.html#property-binding)
Learn more about [property bindings](../guide/template-syntax.html#property-binding)
in the Template Syntax chapter.
学习关于[属性绑定](../guide/template-syntax.html#property-binding)
@ -464,7 +462,7 @@ code-example(language="bash").
完整的`app.component.ts`文件如下:
+makeExample('toh-2/ts/app/app.component.ts', 'pt2', 'app.component.ts')
+makeExample('toh-2/ts/app/app.component.ts', '', 'app.component.ts')
.l-main-section
:marked

View File

@ -41,7 +41,7 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-3')]。
我们要启动TypeScript编译器它会监视文件变更并启动开发服务器。只要敲
code-example(format="." language="bash").
code-example(language="bash").
npm start
:marked
@ -82,7 +82,7 @@ code-example(format="." language="bash").
在`app`目录下添加一个名叫`hero-detail.component.ts`的文件,并且创建`HeroDetailComponent`。代码如下:
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'v1', 'hero-detail.component.ts (初始版本)')(format=".")
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'v1', 'app/hero-detail.component.ts (initial version)')(format=".")
.l-sub-section
:marked
### Naming conventions
@ -100,10 +100,11 @@ code-example(format="." language="bash").
我们的所有组件名都以`Component`结尾。所有组件的文件名都以`.component`结尾。
We spell our file names in lower dash case (AKA "kebab-case") so we don't worry about
We spell our file names in lower **[dash case](../guide/glossary.html#!#dash-case)**
(AKA **[kebab-case](../guide/glossary.html#!#kebab-case)**) so we don't worry about
case sensitivity on the server or in source control.
这里我们使用小写中线命名法(也叫烤串命名法)拼写文件名,所以不用担心它在服务器或者版本控制系统中出现大小写问题。
这里我们使用小写**[中线命名法](../guide/glossary.html#!#dash-case)**(也叫**[烤串命名法](../guide/glossary.html#!#kebab-case)**)拼写文件名,所以不用担心它在服务器或者版本控制系统中出现大小写问题。
<!-- TODO
.l-sub-section
:marked
@ -145,7 +146,8 @@ code-example(format="." language="bash").
`HeroDetailComponent`组件将会有一个`hero`属性,而不是`selectedHero`属性。
所以,我们要把模板中的所有`selectedHero`替换为`hero`。只改这些就够了。
最终结果如下所示:
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'template', 'hero-detail.component.ts (模板)')(format=".")
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'template', 'app/hero-detail.component.ts (template)')(format=".")
:marked
Now our hero detail layout exists only in the `HeroDetailComponent`.
@ -169,16 +171,16 @@ code-example(format="." language="bash").
要解决这个问题,我们也得从`app.component.ts`文件中把`Hero`类移到属于它自己的`hero.ts`文件中。
+makeExample('toh-3/ts/app/hero.ts', null, 'hero.ts (导出Hero类)')(format=".")
+makeExample('toh-3/ts/app/hero.ts', '', 'app/hero.ts')(format=".")
:marked
We export the `Hero` class from `hero.ts` because we'll need to reference it in both component files.
Add the following import statement near the top of both `app.component.ts` and `hero-detail.component.ts`.
Add the following import statement near the top of **both `app.component.ts` and `hero-detail.component.ts`**.
我们得从`hero.ts`中导出`Hero`类,因为我们要从那些组件文件中引用它。
在`app.component.ts`和`hero-detail.component.ts`的顶部添加下列import语句
**`app.component.ts`和`hero-detail.component.ts`**的顶部添加下列import语句
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero-import', 'hero-detail.component.ts与app.component.ts(导入Hero类)')
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero-import')
:marked
#### The *hero* property is an ***input***
@ -268,7 +270,7 @@ code-example(format=".").
`AppComponent`的模板是这样的:
+makeExample('toh-3/ts/app/app.component.ts', 'hero-detail-template', 'app.component.ts (Template)')(format='.')
+makeExample('toh-3/ts/app/app.component.ts', 'hero-detail-template', 'app.component.ts (template)')(format='.')
:marked
Thanks to the binding, the `HeroDetailComponent` should receive the hero from the `AppComponent` and display that hero's detail beneath the list.
The detail should update every time the user picks a new hero.

View File

@ -22,7 +22,7 @@ include ../_util-fns
在这种方式下借助mock服务来对组件进行单元测试也会更容易。
Because data services are invariably asynchronous,
we'll finish the chapter with a promise-based version of the data service.
we'll finish the chapter with a **!{_Promise}**-based version of the data service.
因为数据服务通常都是异步的,所以在本章的最后,我们会把它重构为基于承诺(Promise一种异步编程模式)的版本。
@ -95,7 +95,7 @@ code-example(language="bash").
目前,`AppComponent`显示的是我们自定义的一个mock英雄数据。
我们可改进的地方至少有两个:首先,定义英雄的数据不该是该组件的任务。其次,想把这份英雄列表的数据共享给其它组件和视图可不那么容易。
We can refactor this hero data acquisition business to a single service that provides heroes and
We can refactor this hero data acquisition business to a single service that provides heroes, and
share that service with all components that need heroes.
我们可以把提供英雄数据的任务重构为一个单独的服务,它将提供英雄数据,并且把这个服务在所有需要英雄数据的组件之间共享。
@ -108,7 +108,7 @@ code-example(language="bash").
.l-sub-section
:marked
We've adopted a convention in which we spell the name of a service in lowercase followed by `.service`.
If the service name were multi-word, we'd spell the base filename with lower dash case (AKA "kebab-case").
If the service name were multi-word, we'd spell the base filename in lower [dash-case](../guide/glossary.html#!#dash-case).
The `SpecialSuperHeroService` would be defined in the `special-super-hero.service.ts` file.
我们遵循的文件命名约定是:服务名称的小写形式(基本名),加上`.service`后缀。
@ -119,7 +119,7 @@ code-example(language="bash").
我们把这个类命名为`HeroService`,并且导出它,以供别人使用。
+makeExample('toh-4/ts/app/hero.service.1.ts', 'empty-class', 'hero.service.ts (导出类)')(format=".")
+makeExample('toh-4/ts/app/hero.service.1.ts', 'empty-class', 'app/hero.service.ts (starting point)')(format=".")
:marked
### Injectable Services
@ -150,7 +150,8 @@ code-example(language="bash").
Add a `getHeroes` method stub.
添加一个名叫`getHeros`的桩方法。
+makeExample('toh-4/ts/app/hero.service.1.ts', 'getHeroes-stub', 'hero.service.ts (getHeroes桩方法)')(format=".")
+makeExample('toh-4/ts/app/hero.service.1.ts', 'getHeroes-stub', 'app/hero.service.ts (getHeroes stub)')(format=".")
:marked
We're holding back on the implementation for a moment to make an important point.
@ -184,7 +185,8 @@ code-example(language="bash").
从`app.component.ts`文件中剪切`HEROS`数组,并把它粘贴到`app`目录下一个名叫`mock-heroes.ts`的文件中。
我们还要把`import {Hero}...`语句拷贝过来,因为我们的英雄数组用到了`Hero`类。
+makeExample('toh-4/ts/app/mock-heroes.ts', null, 'mock-heroes.ts (英雄数组)')
+makeExample('toh-4/ts/app/mock-heroes.ts', null, 'app/mock-heroes.ts')
:marked
We export the `HEROES` constant so we can import it elsewhere &mdash; such as our `HeroService`.
@ -194,7 +196,8 @@ code-example(language="bash").
we leave behind an uninitialized `heroes` property:
同时,回到刚剪切出`HEROES`数组的`app.component.ts`文件,我们留下了一个尚未初始化的`heroes`属性:
+makeExample('toh-4/ts/app/app.component.1.ts', 'heroes-prop', 'app.component.ts (heroes属性)')(format=".")
+makeExample('toh-4/ts/app/app.component.1.ts', 'heroes-prop', 'app/app.component.ts (heroes property)')(format=".")
:marked
### Return Mocked Heroes
### 返回模拟的英雄数据
@ -203,7 +206,8 @@ code-example(language="bash").
回到`HeroService`,我们导入`HEROES`常量,并在`getHeroes`方法中返回它。
我们的`HeroService`服务现在看起来是这样:
+makeExample('toh-4/ts/app/hero.service.1.ts', null, 'hero.service.ts')(format=".")
+makeExample('toh-4/ts/app/hero.service.1.ts', null, 'app/hero.service.ts')(format=".")
:marked
### Use the Hero Service
### 使用HeroService服务
@ -214,7 +218,8 @@ code-example(language="bash").
We begin, as usual, by importing the thing we want to use, the `HeroService`.
通常,我们会从导入要用的东西开始,比如`HeroService`。
+makeExample('toh-4/ts/app/app.component.ts', 'hero-service-import', 'app.component.ts (导入HeroService)')
+makeExcerpt('toh-4/ts/app/app.component.ts', 'hero-service-import')
:marked
Importing the service allows us to *reference* it in our code.
How should the `AppComponent` acquire a runtime concrete `HeroService` instance?
@ -223,10 +228,13 @@ code-example(language="bash").
`AppComponent`该如何在运行中获得一个具体的`HeroService`实例呢?
### Do we *new* the *HeroService*? No way!
### 我们要自己 *new* 出这个 *HeroService* 吗?不!
We could create a new instance of the `HeroService` with "new" like this:
We could create a new instance of the `HeroService` with `new` like this:
固然,我们可以使用`new`关键字来创建`HeroService`的实例,就像这样:
+makeExample('toh-4/ts/app/app.component.1.ts', 'new-service')(format=".")
:marked
That's a bad idea for several reasons including
@ -242,7 +250,7 @@ code-example(language="bash").
如果有一天我们修改了`HeroService`的构造函数,我们不得不找出创建过此服务的每一处代码,并修改它。
而给代码打补丁的行为容易导致错误,并增加了测试的负担。
* We create a new service each time we use "new".
* We create a new service each time we use `new`.
What if the service should cache heroes and share that cache with others?
We couldn't do that.
@ -274,15 +282,20 @@ code-example(language="bash").
Two lines replace the one line that created with *new*:
用这两行代码代替用`new`时的一行:
1. we add a constructor.
1. 添加一个构造函数
1. we add to the component's `providers` metadata
1. 添加组件的`providers`元数据
1. We add a constructor that also defines a private property.
1. 我们添加了一个构造函数,同时还定义了一个私有属性。
1. We add to the component's `providers` metadata.
1. 我们添加了组件的`providers`元数据
Here's the constructor:
下面就是这个构造函数:
+makeExample('toh-4/ts/app/app.component.1.ts', 'ctor', 'app.component.ts (构造函数)')
+makeExample('toh-4/ts/app/app.component.1.ts', 'ctor', 'app/app.component.ts (constructor)')
:marked
The constructor itself does nothing. The parameter simultaneously
defines a private `heroService` property and identifies it as a `HeroService` injection site.
@ -305,7 +318,8 @@ code-example(language="bash").
*注入器*还不知道该如何创建`HeroService`。
如果现在运行我们的代码Angular就会失败并报错
code-example(format="." language="html").
code-example(format="nocode").
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService)
(异常没有HeroService的供应商(AppComponent -> HeroService))
:marked
@ -315,7 +329,8 @@ code-example(format="." language="html").
我们还得注册一个`HeroService`**供应商**,来告诉*注入器*如何创建`HeroService`。
要做到这一点,我们应该在`@Component`组件的元数据底部添加`providers`数组属性如下:
+makeExample('toh-4/ts/app/app.component.1.ts', 'providers', 'app.component.ts (提供HeroService)')
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'providers')
:marked
The `providers` array tells Angular to create a fresh instance of the `HeroService` when it creates a new `AppComponent`.
The `AppComponent` can use that service to get heroes and so can every child component of its component tree.
@ -338,7 +353,8 @@ a#child-component
We don't really need a dedicated method to wrap one line. We write it anyway:
在真实的世界中,我们并不需要把一行代码包装成一个专门的方法,但无论如何,我们在演示代码中先这么写:
+makeExample('toh-4/ts/app/app.component.1.ts', 'getHeroes', 'app.component.ts (getHeroes)')(format=".")
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'getHeroes')
<a id="oninit"></a>
:marked
@ -385,13 +401,15 @@ a#child-component
Here's the essential outline for the `OnInit` interface:
这是`OnInit`接口的基本轮廓:
+makeExample('toh-4/ts/app/app.component.1.ts', 'on-init', 'app.component.ts (OnInit协议)')(format=".")
+makeExample('toh-4/ts/app/app.component.1.ts', 'on-init', 'app/app.component.ts (ngOnInit stub)')(format=".")
:marked
We write an `ngOnInit` method with our initialization logic inside and leave it to Angular to call it
at the right time. In our case, we initialize by calling `getHeroes`.
我们写下带有初始化逻辑的`ngOnInit`方法然后留给Angular供其在正确的时机调用。在这个例子中我们通过调用`getHeroes`来完成初始化。
+makeExample('toh-4/ts/app/app.component.1.ts', 'ng-on-init', 'app.component.ts (OnInit协议)')(format=".")
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'ng-on-init')
:marked
Our application should be running as expected, showing a list of heroes and a hero detail view
when we click on a hero name.
@ -402,12 +420,17 @@ a#child-component
我们就快完成了,但还有点事情不太对劲儿。
## Async Services and Promises
<a id="async"></a>
## Async Services and !{_Promise}s
## 异步服务与承诺(Promise)
Our `HeroService` returns a list of mock heroes immediately.
Its `getHeroes` signature is synchronous
我们的`HeroService`立即返回一个模拟的英雄列表,它的`getHeroes`函数签名是同步的。
+makeExample('toh-4/ts/app/app.component.1.ts', 'get-heroes')(format=".")
:marked
Ask for heroes and they are there in the returned result.
@ -427,14 +450,15 @@ a#child-component
我们不得不使用一些异步技术,而这将改变`getHeroes`方法的签名。
We'll use *promises*.
We'll use *!{_Promise}s*.
我们将使用 *承诺(Promise)* 。
### The Hero Service makes a promise
### The Hero Service makes a !{_Promise}
### `HeroService`会生成一个承诺
A **promise** is ... well it's a promise to call us back later when the results are ready.
A **!{_Promise}** is ... well it's a promise to call us back later when the results are ready.
We ask an asynchronous service to do some work and give it a callback function.
It does that work (somewhere) and eventually it calls our function with the results of the work or an error.
@ -447,36 +471,42 @@ a#child-component
这里只是粗浅的说说,要了解更多,请参见[这里](http://exploringjs.com/es6/ch_promises.html)或在Web上搜索其它学习资源。
:marked
Update the `HeroService` with this promise-returning `getHeroes` method:
Update the `HeroService` with this !{_Promise}-returning `getHeroes` method:
把`HeroService`的`getHeroes`方法改写为返回承诺的形式:
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes', 'hero.service.ts (getHeroes)')(format=".")
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes', 'app/hero.service.ts (excerpt)')(format=".")
:marked
We're still mocking the data. We're simulating the behavior of an ultra-fast, zero-latency server,
by returning an **immediately resolved promise** with our mock heroes as the result.
by returning an **immediately resolved !{_Promise}** with our mock heroes as the result.
我们继续使用模拟数据。我们通过返回一个 *立即解决的承诺* 的方式,模拟了一个超快、零延迟的超级服务器。
### Act on the Promise
### Act on the !{_Promise}
### 基于承诺的行动
Returning to the `AppComponent` and its `getHeroes` method, we see that it still looks like this:
回到`AppComponent`和它的`getHeroes`方法,我们看到它看起来还是这样的:
+makeExample('toh-4/ts/app/app.component.1.ts', 'getHeroes', 'app.component.ts (getHeroes - 老的)')(format=".")
+makeExample('toh-4/ts/app/app.component.1.ts', 'getHeroes', 'app/app.component.ts (getHeroes - old)')(format=".")
:marked
As a result of our change to `HeroService`, we're now setting `this.heroes` to a promise rather than an array of heroes.
As a result of our change to `HeroService`, we're now setting `this.heroes` to a !{_Promise} rather than an array of heroes.
在修改了`HeroService`之后,我们还要把`this.heroes`替换为一个承诺,而不再是一个英雄数组。
We have to change our implementation to *act on the promise when it resolves*.
When the promise resolves successfully, *then* we will have heroes to display.
We have to change our implementation to *act on the !{_Promise} when it resolves*.
When the !{_Promise} resolves successfully, *then* we will have heroes to display.
我们得修改这个实现,把它变成*基于承诺*的,并在承诺的事情被解决时再行动。
一旦承诺的事情被成功解决,我们就会显示英雄数据。
We pass our callback function as an argument to the promise's **then** method:
We pass our callback function as an argument to the !{_Promise}'s **then** method:
我们把回调函数作为参数传给承诺对象的**then**函数:
+makeExample('toh-4/ts/app/app.component.ts', 'get-heroes', 'app.component.ts (getHeroes - 修改版)')(format=".")
+makeExample('toh-4/ts/app/app.component.ts', 'get-heroes', 'app/app.component.ts (getHeroes - revised)')(format=".")
.l-sub-section
:marked
The [ES2015 arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
@ -520,6 +550,8 @@ a#child-component
.file typings ...
.file index.html
.file package.json
.file styles.css
.file systemjs.config.js
.file tsconfig.json
.file typings.json
:marked
@ -543,16 +575,25 @@ a#child-component
来盘点一下我们已经构建完的部分。
* We created a service class that can be shared by many components
* 我们创建了一个能被多个组件共享的服务类
* We used the `ngOnInit` Lifecycle Hook to get our heroes when our `AppComponent` activates
* We created a service class that can be shared by many components.
* 我们创建了一个能被多个组件共享的服务类。
* We used the `ngOnInit` Lifecycle Hook to get our heroes when our `AppComponent` activates.
* 我们使用`ngOnInit`生命周期钩子,以便在`AppComponent`激活时获取英雄数据。
* We defined our `HeroService` as a provider for our `AppComponent`
* 我们把`HeroService`定义为`AppComponent`的一个供应商
* We created mock hero data and imported them into our service
* 我们创建了一个模拟的英雄数据,并把它导入我们的服务中
* We designed our service to return a promise and our component to get our data from the promise
* 我们把服务改造为返回承诺的,并让组件从承诺获取数据
* We defined our `HeroService` as a provider for our `AppComponent`.
* 我们把`HeroService`定义为`AppComponent`的一个供应商。
* We created mock hero data and imported them into our service.
* 我们创建了一个模拟的英雄数据,并把它导入我们的服务中。
* We designed our service to return a !{_Promise} and our component to get our data from the !{_Promise}.
* 我们把服务改造为返回承诺的,并让组件从承诺获取数据。
p Run the #[+liveExampleLink2('', 'toh-4')] for this part.
@ -586,10 +627,11 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
Import the `Hero` symbol and add the following `getHeroesSlowly` method to the `HeroService`
导入`Hero`类,并且在`HeroService`中添加如下的`getHeroesSlowly`方法:
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes-slowly', 'hero.service.ts (getHeroesSlowly)')(format=".")
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes-slowly', 'app/hero.service.ts (getHeroesSlowly)')(format=".")
:marked
Like `getHeroes`, it also returns a promise.
But this promise waits 2 seconds before resolving the promise with mock heroes.
Like `getHeroes`, it also returns a !{_Promise}.
But this !{_Promise} waits 2 seconds before resolving the !{_Promise} with mock heroes.
像`getHeroes`一样,它也返回一个承诺。
但是,这个承诺会在使用模拟数据完成任务之前等待两秒钟。

View File

@ -6,13 +6,13 @@ include ../_util-fns
We received new requirements for our Tour of Heroes application:
我们收到了一份《英雄指南》的新需求:
* add a *Dashboard* view.
* Add a *Dashboard* view.
* 添加一个*仪表盘*视图。
* navigate between the *Heroes* and *Dashboard* views.
* Navigate between the *Heroes* and *Dashboard* views.
* 在*英雄列表*和*仪表盘*视图之间导航。
* clicking on a hero in either view navigates to a detail view of the selected hero.
* Clicking on a hero in either view navigates to a detail view of the selected hero.
* 无论在哪个视图中点击一个英雄,都会导航到该英雄的详情页。
* clicking a *deep link* in an email opens the detail view for a particular hero;
* Clicking a *deep link* in an email opens the detail view for a particular hero;
* 在邮件中点击一个*深链接*,会直接打开一个特定英雄的详情视图。
When were done, users will be able to navigate the app like this:
@ -92,14 +92,14 @@ code-example(language="bash").
下面是我们的计划
* turn `AppComponent` into an application shell that only handles navigation.
* 把`AppComponent`变成应用程序的“壳”,它只处理导航
* relocate the *Heroes* concerns within the current `AppComponent` to a separate `HeroesComponent`
* 把现在由`AppComponent`关注的*英雄们*移到一个独立的`HeroesComponent`中
* add routing
* 添加路由
* create a new `DashboardComponent`
* 添加一个新的`DashboardComponent`组件
* turn `AppComponent` into an application shell that only handles navigation,
* 把`AppComponent`变成应用程序的“壳”,它只处理导航
* relocate the *Heroes* concerns within the current `AppComponent` to a separate `HeroesComponent`,
* 把现在由`AppComponent`关注的*英雄们*移到一个独立的`HeroesComponent`中
* add routing,
* 添加路由
* create a new `DashboardComponent`,
* 添加一个新的`DashboardComponent`组件
* tie the *Dashboard* into the navigation structure.
* 把*仪表盘*加入导航结构中。
@ -148,7 +148,7 @@ code-example(language="bash").
* 把`my-app`选择器改名为`my-heroes`。
:marked
+makeExample('toh-5/ts/app/heroes.component.ts', 'heroes-component-renaming', 'app/heroes.component.ts (改名)')(format=".")
+makeExample('toh-5/ts/app/heroes.component.ts', 'heroes-component-renaming', 'app/heroes.component.ts (showing renamings only)')(format=".")
:marked
## Create *AppComponent*
@ -249,12 +249,14 @@ code-example(language="bash").
and a configuration decorator (`RouteConfig`). We'll import them all together:
Angular路由器是由多个服务(`ROUTER_PROVIDERS`)和多个指令(`ROUTER_DIRECTIVES`)以及一个配置装饰器(`RouteConfig`)组成的。我们一次性导入它们。
+makeExample('toh-5/ts/app/app.component.2.ts', 'import-router', 'app.component.ts (导入router)')(format=".")
+makeExample('toh-5/ts/app/app.component.2.ts', 'import-router', 'app/app.component.ts (router imports)')(format=".")
:marked
Next we update the `directives` and `providers` metadata arrays to *include* the router assets.
接下来,我们要更新`directives`和`providers`元数据数组,来包含这些路由器部件。
+makeExample('toh-5/ts/app/app.component.2.ts', 'directives-and-providers', 'app.component.ts (directives和providers)')(format=".")
+makeExample('toh-5/ts/app/app.component.2.ts', 'directives-and-providers', 'app/app.component.ts (directives and providers)')(format=".")
:marked
Notice that we also removed the `HeroesComponent` from the `directives` array.
`AppComponent` no longer shows heroes; that will be the router's job.
@ -279,7 +281,8 @@ code-example(language="bash").
Let's define our first route, a route to the `HeroesComponent`.
我们来定义第一个路由 —— 到`HeroesComponent`的路由。
+makeExample('toh-5/ts/app/app.component.2.ts', 'route-config', 'app.component.ts (英雄列表的RouteConfig)')(format=".")
+makeExample('toh-5/ts/app/app.component.2.ts', 'route-config', 'app/app.component.ts (RouteConfig for heroes)')(format=".")
:marked
`@RouteConfig` takes an array of *route definitions*.
We have only one route definition at the moment but rest assured, we'll add more.
@ -337,7 +340,8 @@ code-example(language="bash").
The revised template looks like this:
修改过的模板是这样的:
+makeExample('toh-5/ts/app/app.component.2.ts', 'template', 'app.component.ts (英雄列表模板)')(format=".")
+makeExample('toh-5/ts/app/app.component.2.ts', 'template', 'app/app.component.ts (template v1)')(format=".")
:marked
Notice the `[routerLink]` binding in the anchor tag.
We bind the `RouterLink` directive (another of the `ROUTER_DIRECTIVES`) to an array
@ -418,7 +422,8 @@ code-example(language="bash").
Add the following `'Dashboard'` route definition to the `@RouteConfig` array of definitions.
然后把下列`'Dashboard'`路由的定义添加到`@RouteConfig`数组中。
+makeExample('toh-5/ts/app/app.component.ts','dashboard-route', 'app.component.ts (仪表盘路由)')(format=".")
+makeExample('toh-5/ts/app/app.component.ts','dashboard-route', 'app/app.component.ts (Dashboard route)')(format=".")
.l-sub-section
:marked
**useAsDefault**
@ -440,7 +445,7 @@ code-example(language="bash").
最后,在模板上添加一个到仪表盘的导航链接,就放在*英雄(Heroes)*链接的上方。
+makeExample('toh-5/ts/app/app.component.ts','template', 'app.component.ts (模板)')(format=".")
+makeExample('toh-5/ts/app/app.component.ts','template', 'app/app.component.ts (template)')(format=".")
.l-sub-section
:marked
We nestled the two links within `<nav>` tags.
@ -478,7 +483,8 @@ code-example(language="bash").
Create that file with these contents:
使用下列内容创建文件:
+makeExample('toh-5/ts/app/dashboard.component.html', null, 'dashboard.component.html')(format=".")
+makeExample('toh-5/ts/app/dashboard.component.html', null, 'app/dashboard.component.html')(format=".")
:marked
We use `*ngFor` once again to iterate over a list of heroes and display their names.
We added extra `<div>` elements to help with styling later in this chapter.
@ -506,10 +512,10 @@ code-example(language="bash").
回忆一下,在前面的章节中,我们从`HeroesComponent`的`providers`数组中移除了`HeroService`服务,并把它添加到顶级组件`AppComponent`的`providers`数组中。
That move created a singleton `HeroService` instance, available to *all* components of the application.
We'll inject and use it here in the `DashboardComponent` .
Angular will inject `HeroService` and we'll use it here in the `DashboardComponent`.
这个改动创建了一个`HeroService`的单例对象,它对应用中的*所有*组件都有效。
在`DashboardComponent`组件中,我们要把它注入进来,并使用它
在`DashboardComponent`组件中,Angular会把`HeroService`注入进来,我们就能在`DashboardComponent`中使用它了
### Get heroes
### 获取英雄数组
@ -614,7 +620,8 @@ code-example(format='').
Here's the *route definition* we'll use.
下面是我们将使用的*路由定义*。
+makeExample('toh-5/ts/app/app.component.ts','hero-detail-route', 'app/app.component.ts (到HeroDetailComponent的路由)')(format=".")
+makeExample('toh-5/ts/app/app.component.ts','hero-detail-route', 'app/app.component.ts (route to HeroDetailComponent)')(format=".")
:marked
The colon (:) in the path indicates that `:id` is a placeholder to be filled with a specific hero `id`
when navigating to the `HeroDetailComponent`.
@ -654,10 +661,11 @@ code-example(format='').
## Revise the *HeroDetailComponent*
## 修改*HeroDetailComponent*
Before we rewrite the `HeroDetailComponent`, let's remember what it looks like now:
Before we rewrite the `HeroDetailComponent`, let's review what it looks like now:
在重写`HeroDetailComponent`之前,我们先记住它现在的样子:
+makeExample('toh-4/ts/app/hero-detail.component.ts', null, 'app/hero-detail.component.ts (当前)')
在重写`HeroDetailComponent`之前,我们先看看它现在的样子:
+makeExample('toh-4/ts/app/hero-detail.component.ts', null, 'app/hero-detail.component.ts (current)')
:marked
The template won't change. We'll display a hero the same way. The big changes are driven by how we get the hero.
@ -665,7 +673,7 @@ code-example(format='').
We will no longer receive the hero in a parent component property binding.
The new `HeroDetailComponent` should take the `id` parameter from the router's `RouteParams` service
and use the `HeroService` to fetch the hero with that `id` from storage.
and use the `HeroService` to fetch the hero with that `id`.
我们不会再从父组件的属性绑定中取得英雄数据。
新的`HeroDetailComponent`应该从路由器的`RouteParams`服务中取得`id`参数,并通过`HeroService`服务获取具有这个指定`id`的英雄数据。
@ -675,7 +683,7 @@ code-example(format='').
我们需要一个import语句来引用`RouteParams`。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'import-route-params')(format=".")
:marked
We import the `HeroService`so we can fetch a hero`.
We import the `HeroService`so we can fetch a hero.
我们导入了`HeroService`,现在就能获取一个英雄了。
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'import-hero-service')(format=".")
@ -775,15 +783,18 @@ code-example(format='').
Here's the (nearly) finished `HeroDetailComponent`:
下面是(几乎)完成的`HeroDetailComponent`
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'v2', 'app/hero-detail.component.ts (最新版)')(format=".")
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'v2', 'app/hero-detail.component.ts (latest)')(format=".")
:marked
.l-main-section
:marked
## Select a *Dashboard* Hero
## 选择一个*仪表盘*中的英雄
When a user selects a hero in the dashboard, the app should navigate to the `HeroDetailComponent` to view and edit the selected hero..
When a user selects a hero in the dashboard, the app should navigate to the `HeroDetailComponent` to view and edit the selected hero.
当用户从仪表盘中选择了一位英雄时,本应用要导航到`HeroDetailComponent`以查看和编辑所选的英雄。
@ -823,7 +834,7 @@ code-example(format='').
+makeExample('toh-5/ts/app/app.component.ts','hero-detail-route', 'app/app.component.ts (英雄详情路由)')(format=".")
:marked
The `DashboardComponent` doesn't have the router yet. We obtain it in the usual way:
`import` the `router` reference and inject it in the constructor (along with the `HeroService`):
import the `router` reference and inject it in the constructor (along with the `HeroService`):
`DashboardComponent`还没有路由器。我们使用常规的方式为它加上路由:
`import` `router`对象的引用,并且把它注入到构造函数中(就像`HeroService`那样)
@ -884,7 +895,7 @@ figure.image-display
### 使用*UpperCasePipe*格式化
Notice that the hero's name is displayed in CAPITAL LETTERS. That's the effect of the `UpperCasePipe`
that we slipped into the interpolation binding. Look for it right after the pipe operator, ( | ).
that we slipped into the interpolation binding. Look for it right after the pipe operator ( | ).
注意,英雄的名字全被显示成大写字母。那是 `UpperCasePipe`的效果,借助它,我们能插手“插值表达式绑定”的过程。去管道操作符 ( | ) 后面找它。
+makeExample('toh-5/ts/app/heroes.component.html','pipe')(format=".")
@ -931,9 +942,10 @@ figure.image-display
所以我们可以从元数据的`directives`数组中移除它。`directives`数组现在没东西了,因此我们也把它删掉。
我们也同样可以删掉`import` `HeroDetailComponent`的语句。
The revised component metadata looks like this:
The revised `@Component` looks like this:
修改过的`@Component`是这样的:
修改过的组件数据是这样的:
+makeExample('toh-5/ts/app/heroes.component.ts', 'metadata', 'app/heroes.component.ts (revised metadata)')(format=".")
:marked
Now we can see what's going on as we update the component class along the same lines as the dashboard:
@ -944,7 +956,7 @@ figure.image-display
1. Inject the `router` in the constructor (along with the `HeroService`)
1. 把`router`注入到构造函数中(就像`HeroService`那样)
1. Implement the `gotoDetail` method by calling the `router.navigate` method
with a two-part 'HeroDetail' *link parameters array*.
with a two-part `HeroDetail` *link parameters array*.
1. 实现`gotoDetail`方法:以`HeroDetail`和*链接参数数组*为参数调用`router.navigate`方法。
Here's the revised component class:
@ -1038,7 +1050,8 @@ figure.image-display
Add a `app.component.css` file to the `app` folder with the following content.
在`app`目录下添加一个`app.component.css`文件,内容如下:
+makeExample('toh-5/ts/app/app.component.css', 'css', 'app/app.component.css (导航样式)')
+makeExample('toh-5/ts/app/app.component.css', '', 'app/app.component.css (navigation styles)')
.l-sub-section
:marked
**The *router-link-active* class**
@ -1070,16 +1083,31 @@ figure.image-display
我们也可以在所有组件之外创建*应用级*样式。
Our designers provided some basic styles to apply to elements across the entire app.
Add the following to a new file named `styles.css` in the root folder.
These correspond to the full set of master styles that we
introduced earlier (see
[QuickStart, "Add some style"](../quickstart.html#!#add-some-style)).
Here is an excerpt.
我们的设计师提供了一组基础样式,这些样式应用到的元素横跨整个应用。
把下面这个名叫`styles.css`的新文件添加到根目录中:
+makeExample('toh-5/ts/styles.1.css', '', 'styles.css (应用级样式)')(format=".")
这些和我们前面引入的主样式全集是一样的(参见
[快速起步, "添加一些样式"](../quickstart.html#!#add-some-style))。
下面是摘录:
+makeExample('toh-5/ts/styles.1.css', 'toh-excerpt', 'styles.css (app styles excerpt)')(format=".")
- var styles_css = 'https://raw.githubusercontent.com/angular/angular.io/master/public/docs/_examples/styles.css'
:marked
Reference this stylesheet within the `index.html` in the traditional manner.
Add a new file named `styles.css` in the root folder, if there isn't one already.
Ensure that it contains the [master styles given here](!{styles_css}).
如果在根目录下没有一个名叫`styles.css`的文件,就添加它。
确保它包含[这里给出的主样式](!{styles_css})。
Also ensure this stylesheet is referenced in the traditional manner within `index.html`.
同时确保这个样式表在`index.html`中被使用传统方式引用了。
用传统的方式,在`index.html`中引用这个样式表。
+makeExample('toh-5/ts/index.html','css', 'index.html (link ref)')(format=".")
:marked
Look at the app now. Our dashboard, heroes, and navigation links are styling!
@ -1132,7 +1160,6 @@ p.
.file systemjs.config.json
.file tsconfig.json
.file typings.json
:marked
.l-main-section
:marked
@ -1144,17 +1171,29 @@ p.
We travelled a great distance in this chapter.
在本章中,我们往前走了很远:
- We added the Angular *Component Router* to navigate among different components.
- 我们添加了Angular*组件路由器*在各个不同组件之间导航。
- We learned how to create router links to represent navigation menu items
- We learned how to create router links to represent navigation menu items.
- 我们学会了如何创建路由链接来表示导航栏的菜单项。
- We used router parameters to navigate to the details of user selected hero
- We used router parameters to navigate to the details of user selected hero.
- 我们使用路由参数来导航到用户所选的英雄详情。
- We shared the `HeroService` among multiple components
- We shared the `HeroService` among multiple components.
- 我们在多个组件之间共享了`HeroService`服务。
- We moved HTML and CSS out of the component file and into their own files.
- 我们把HTML和CSS从组件中移出来放到了它们自己的文件中。
- We added the `uppercase` pipe to format data
- We added the `uppercase` pipe to format data.
- 我们添加了一个`uppercase`管道,来格式化数据。
### The Road Ahead
@ -1165,8 +1204,8 @@ p.
我们有了很多用于构建应用的基石。
但我们仍然缺少很关键的一块儿:远程数据存取。
In a forthcoming tutorial chapter,
In the next chapter,
well replace our mock data with data retrieved from a server using http.
即将到来的章节中我们将从硬编码模拟数据改为使用http服务从服务器获取数据。
下一章我们将从硬编码模拟数据改为使用http服务从服务器获取数据。

View File

@ -80,7 +80,7 @@ code-example(language="bash").
.alert.is-helpful
:marked
This chaper is an introduction to the Angular http client.
This chapter is an introduction to the Angular http client.
Please don't be distracted by the details of this backend substitution. Just follow along with the example.
Learn more later about the *in-memory web api* in the [Http chapter](../guide/server-communication.html#!#in-mem-web-api).
@ -217,6 +217,11 @@ code-example(language="bash").
Loading heroes using `Http` required no changes outside of `HeroService`, but we added a few new features as well.
In the following section we will update our components to use our new methods to add, edit and delete heroes.
Before we can add those methods, we need to initialize some variables with their respective imports.
+makeExample('toh-6/ts/app/hero-detail.component.ts', 'variables-imports', 'app/hero-detail.component.ts')(format=".")
:marked
### Add/Edit in the *HeroDetailComponent*
We already have `HeroDetailComponent` for viewing details about a specific hero.