Merge remote-tracking branch 'angular.io/master'

# Conflicts:
#	README.md
#	public/_includes/_footer.jade
#	public/_includes/_hero-home.jade
#	public/docs/ts/latest/cookbook/a1-a2-quick-reference.jade
#	public/docs/ts/latest/glossary.jade
#	public/docs/ts/latest/guide/architecture.jade
#	public/docs/ts/latest/guide/dependency-injection.jade
#	public/docs/ts/latest/guide/forms.jade
#	public/docs/ts/latest/guide/router.jade
#	public/docs/ts/latest/guide/style-guide.jade
#	public/docs/ts/latest/testing/first-app-tests.jade
#	public/docs/ts/latest/testing/jasmine-testing-101.jade
#	public/docs/ts/latest/tutorial/toh-pt5.jade
This commit is contained in:
Zhimin YE (Rex) 2016-07-15 15:52:34 +01:00
commit 0e14785cba
108 changed files with 1206 additions and 1361 deletions

View File

@ -10,20 +10,24 @@ env:
- DBUS_SESSION_BUS_ADDRESS=/dev/null
- DISPLAY=:99.0
- CHROME_BIN=chromium-browser
- LATEST_RELEASE=2.0.0-rc.4
matrix:
- SCRIPT=lint
- SCRIPT="run-e2e-tests --fast"
- SCRIPT="run-e2e-tests --fast" PREVIEW=true
- TASK=lint
- TASK="run-e2e-tests --fast" SCRIPT=examples-install.sh
- TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh
- TASK=harp-compile SCRIPT=deploy-install.sh
- TASK=harp-compile SCRIPT=deploy-install-preview.sh
matrix:
fast_finish: true
allow_failures:
- env: "SCRIPT=\"run-e2e-tests --fast\" PREVIEW=true"
- env: "TASK=\"run-e2e-tests --fast\" SCRIPT=examples-install-preview.sh"
- env: "TASK=harp-compile SCRIPT=deploy-install-preview.sh"
before_install:
- npm install -g gulp --no-optional
install:
- npm install --no-optional
- if [[ $SCRIPT ]]; then ./scripts/$SCRIPT; fi
before_script:
- sh -e /etc/init.d/xvfb start
install:
- ./scripts/install.sh
- if [[ $PREVIEW == true ]]; then npm install --prefix public/docs/_examples angular/{core,common,compiler,platform-browser,platform-browser-dynamic,http,forms,router-deprecated,router,upgrade}-builds; fi
script:
- gulp $SCRIPT
- gulp $TASK

View File

@ -403,7 +403,9 @@ gulp.task('add-example-boilerplate', function() {
// copies boilerplate files to locations
// where an example app is found
gulp.task('_copy-example-boilerplate', copyExampleBoilerplate);
gulp.task('_copy-example-boilerplate', function () {
if (!argv.fast) copyExampleBoilerplate();
});
// copies boilerplate files to locations
@ -451,6 +453,36 @@ gulp.task('remove-example-boilerplate', function() {
deleteExampleBoilerPlate();
});
// Npm install Angular libraries into examples/node_modules,
// either release or current build packages
// Examples:
// gulp install-example-angular --build // use current build packages
// gulp install-example-angular // restore release packages
gulp.task('install-example-angular', installExampleAngular);
function installExampleAngular() {
var sources;
var template;
var libs = [
'core', 'common', 'compiler',
'platform-browser', 'platform-browser-dynamic',
'forms', 'http', 'router', 'upgrade'];
// Like: "angular/core-builds" or "@angular/core"
sources = libs.map( lib => argv.build ? `angular/${lib}-builds` : `@angular/${lib}`);
sources.push('@angular/router-deprecated');
gutil.log(`Installing Angular npm packages from ${argv.build ? 'BUILD' : 'RELEASE'}`);
var spawnInfo = spawnExt('rm', ['-rf', 'node_modules/@angular'], { cwd: EXAMPLES_PATH});
return spawnInfo.promise
.then(() => {
spawnInfo = spawnExt('npm', ['install', ...sources], {cwd: EXAMPLES_PATH});
return spawnInfo.promise
});
}
// deletes boilerplate files that were added by copyExampleBoilerplate
// from locations where an example app is found
gulp.task('_delete-example-boilerplate', deleteExampleBoilerPlate);
@ -564,16 +596,16 @@ gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){
});
});
gulp.task('harp-compile', ['build-docs'], function() {
return harpCompile();
});
gulp.task('check-deploy', ['build-docs'], function() {
return harpCompile().then(function() {
gutil.log('compile ok');
if(argv.dryRun) {
return false;
} else {
gutil.log('running live server ...');
execPromise('npm run live-server ./www');
return askDeploy();
}
gutil.log('running live server ...');
execPromise('npm run live-server ./www');
return askDeploy();
}).then(function(shouldDeploy) {
if (shouldDeploy) {
gutil.log('deploying...');
@ -596,7 +628,18 @@ gulp.task('test-api-builder', function (cb) {
// angular.io: gulp link-checker
// local site: gulp link-checker --url=http://localhost:3000
gulp.task('link-checker', function(done) {
return linkChecker();
var method = 'get'; // the default 'head' fails for some sites
var exclude = [
// Dart API docs aren't working yet; ignore them
'*/dart/latest/api/*',
// Somehow the link checker sees ng1 {{...}} in the resource page; ignore it
'resources/%7B%7Bresource.url%7D%7D',
// API docs have links directly into GitHub repo sources; these can
// quickly become invalid, so ignore them for now:
'*/angular/tree/*'
];
var blcOptions = { requestMethod: method, excludedKeywords: exclude};
return linkChecker({ blcOptions: blcOptions });
});
@ -727,12 +770,8 @@ function linkChecker(options) {
var blcOptions = options.blcOptions || {};
var customData = options.customData || {};
var excludeBad; // don't bother reporting bad links matching this RegExp
if (argv.excludeBad) {
excludeBad = new RegExp(argv.excludeBad);
} else {
excludeBad = options.excludeBad === undefined ? /docs\/dart\/latest\/api/ : '';
}
// don't bother reporting bad links matching this RegExp
var excludeBad = argv.excludeBad ? new RegExp(argv.excludeBad) : (options.excludeBad || '');
var previousPage;
var siteUrl = argv.url || options.url || 'https://angular.io/';
@ -779,7 +818,8 @@ function linkChecker(options) {
var outputFile = path.join(process.cwd(), 'link-checker-results.txt');
var header = 'Link checker results for: ' + siteUrl +
'\nStarted: ' + (new Date()).toLocaleString() +
'\nSkipping bad links matching regex: ' +excludeBad.toString() + '\n\n';
'\nExcluded links (blc file globs): ' + blcOptions.excludedKeywords +
'\nExcluded links (custom --exclude-bad regex): ' + excludeBad.toString() + '\n\n';
gutil.log(header);
fs.writeFileSync(outputFile, header);
@ -1030,7 +1070,7 @@ function buildApiDocs(targetLanguage) {
try {
// Build a specialized package to generate different versions of the API docs
var package = new Package('apiDocs', [require(path.resolve(TOOLS_PATH, 'api-builder/angular.io-package'))]);
package.config(function(log, targetEnvironments, writeFilesProcessor, readTypeScriptModules) {
package.config(function(log, targetEnvironments, writeFilesProcessor, readTypeScriptModules, linkDocsInlineTagDef) {
log.level = _dgeniLogLevel;
ALLOWED_LANGUAGES.forEach(function(target) { targetEnvironments.addAllowed(target); });
if (targetLanguage) {
@ -1040,7 +1080,9 @@ function buildApiDocs(targetLanguage) {
// Don't read TypeScript modules if we are not generating API docs - Dart I am looking at you!
readTypeScriptModules.$enabled = false;
}
writeFilesProcessor.outputFolder = targetLanguage + '/latest/api';
linkDocsInlineTagDef.lang = targetLanguage;
linkDocsInlineTagDef.vers = 'latest';
writeFilesProcessor.outputFolder = path.join(targetLanguage, linkDocsInlineTagDef.vers, 'api');
}
});

View File

@ -34,7 +34,7 @@
"codelyzer": "0.0.22",
"del": "^2.2.0",
"dgeni": "^0.4.0",
"dgeni-packages": "^0.13.0",
"dgeni-packages": "^0.13.1",
"diff": "^2.1.3",
"fs-extra": "^0.30.0",
"globby": "^4.0.0",

View File

@ -255,7 +255,7 @@ describe('Animation Tests', () => {
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
expect(li.getCssValue('opacity')).toMatch('1');
removeHero();
removeHero(700);
expect(li.isPresent()).toBe(false);
});
@ -289,19 +289,22 @@ describe('Animation Tests', () => {
});
});
function addActiveHero() {
function addActiveHero(sleep?: number) {
sleep = sleep || 500;
element(by.buttonText('Add active hero')).click();
browser.driver.sleep(500);
browser.driver.sleep(sleep);
}
function addInactiveHero() {
function addInactiveHero(sleep?: number) {
sleep = sleep || 500;
element(by.buttonText('Add inactive hero')).click();
browser.driver.sleep(500);
browser.driver.sleep(sleep);
}
function removeHero() {
function removeHero(sleep?: number) {
sleep = sleep || 500;
element(by.buttonText('Remove hero')).click();
browser.driver.sleep(500);
browser.driver.sleep(sleep);
}
function getScaleX(el: protractor.ElementFinder) {

View File

@ -0,0 +1,15 @@
// #docregion import
import 'package:angular2/core.dart';
// #enddocregion import
import 'hero_list_component.dart';
import 'sales_tax_component.dart';
@Component(
selector: 'my-app',
template: '''
<hero-list></hero-list>
<sales-tax></sales-tax>''',
directives: const [HeroListComponent, SalesTaxComponent])
// #docregion export
class AppComponent { }

View File

@ -1,4 +1,5 @@
// #docregion
import 'dart:async';
import 'package:angular2/core.dart';
import 'hero.dart';
@ -6,19 +7,22 @@ import 'logger_service.dart';
@Injectable()
class BackendService {
static final _mockHeroes = [
new Hero('Windstorm', 'Weather mastery'),
new Hero('Mr. Nice', 'Killing them with kindness'),
new Hero('Magneta', 'Manipulates metalic objects')
];
final Logger _logger;
List getAll(type) {
// TODO get from the database and return as a promise
if (type == Hero) {
return [
new Hero('Windstorm', power: 'Weather mastery'),
new Hero('Mr. Nice', power: 'Killing them with kindness'),
new Hero('Magneta', power: 'Manipulates metalic objects')
];
}
_logger.error('Cannot get object of this type');
throw new ArgumentError("TODO: put log content here");
}
BackendService(Logger this._logger);
Future<List> getAll(type) {
// TODO get from the database
if (type == Hero) return new Future.value(_mockHeroes);
var msg = 'Cannot get object of this type';
_logger.error(msg);
throw new Exception(msg);
}
}

View File

@ -1,11 +1,7 @@
// #docregion
class Hero {
static int _nextId = 1;
int id;
String name;
String power;
final int id;
String name, power;
Hero(this.name, {this.power}) {
id = _nextId++;
}
Hero(this.name, [this.power = '']) : id = _nextId++;
}

View File

@ -1,9 +1,11 @@
// #docregion
import 'package:angular2/core.dart';
import 'hero.dart';
@Component(selector: 'hero-detail', templateUrl: 'hero_detail_component.html')
@Component(
selector: 'hero-detail',
templateUrl: 'hero_detail_component.html')
class HeroDetailComponent {
@Input() Hero hero;
@Input()
Hero hero;
}

View File

@ -2,8 +2,8 @@
<h4>{{hero.name}} Detail</h4>
<div>Id: {{hero.id}}</div>
<div>Name:
<!-- #docregion ng-model -->
<input [(ngModel)]="hero.name"></div>
<!-- #enddocregion ng-model -->
<div>Power:<input [(ngModel)]="hero.power">
<!-- #docregion ngModel -->
<input [(ngModel)]="hero.name">
<!-- #enddocregion ngModel -->
</div>
<div>Power:<input [(ngModel)]="hero.power"></div>

View File

@ -1,4 +1,3 @@
// #docplaster
import 'package:angular2/core.dart';
import 'hero.dart';
@ -6,32 +5,31 @@ import 'hero_detail_component.dart';
import 'hero_service.dart';
// #docregion metadata
// #docregion providers
@Component(
// #enddocregion providers
selector: 'hero-list',
templateUrl: 'hero_list_component.html',
directives: const [HeroDetailComponent],
// #docregion providers
providers: const [HeroService])
// #enddocregion providers
// #enddocregion metadata
/*
// #docregion metadata, providers
class HeroListComponent { ... }
// #enddocregion metadata, providers
*/
// #docregion providers
providers: const [HeroService]
// #enddocregion providers
)
// #docregion class
class HeroListComponent {
class HeroListComponent implements OnInit {
// #enddocregion metadata
List<Hero> heroes;
Hero selectedHero;
// #docregion ctor
HeroListComponent(HeroService heroService) {
heroes = heroService.getHeroes();
// #docregion ctor
final HeroService _heroService;
HeroListComponent(this._heroService);
// #enddocregion ctor
void ngOnInit() {
heroes = _heroService.getHeroes();
}
// #enddocregion ctor
selectHero(Hero hero) {
void selectHero(Hero hero) {
selectedHero = hero;
}
// #docregion metadata
}
// #enddocregion class

View File

@ -1,8 +1,11 @@
<!-- #docregion -->
<h2>Hero List</h2>
<div *ngFor="let hero of heroes" (click)="selectHero(hero)">
{{hero.name}}
</div>
<p><i>Pick a hero from the list</i></p>
<ul>
<li *ngFor="let hero of heroes" (click)="selectHero(hero)">
{{hero.name}}
</li>
</ul>
<hero-detail *ngIf="selectedHero != null" [hero]="selectedHero"></hero-detail>

View File

@ -1,10 +1,9 @@
<!--#docregion binding -->
<div ... >{{hero.name}}</div>
<hero-detail ... [hero]="selectedHero"></hero-detail>
<div ... (click)="selectHero(hero)">...</div>
<li>{{hero.name}}</li>
<hero-detail [hero]="selectedHero"></hero-detail>
<li (click)="selectHero(hero)"></li>
<!--#enddocregion binding -->
<!--#docregion structural -->
<div *ngFor="let hero of heroes" ...>...</div>
<hero-detail *ngIf="selectedHero != null" ...></hero-detail>
<!--#enddocregion structural -->
<li *ngFor="let hero of heroes"></li>
<hero-detail *ngIf="selectedHero != null"></hero-detail>

View File

@ -4,16 +4,20 @@ import 'backend_service.dart';
import 'hero.dart';
import 'logger_service.dart';
// #docregion class
@Injectable()
// #docregion class
class HeroService {
final BackendService _backendService;
final Logger _logger;
HeroService(Logger this._logger, BackendService this._backendService);
final List<Hero> heroes = [];
HeroService(this._logger, this._backendService);
List<Hero> getHeroes() {
List<Hero> heroes = _backendService.getAll(Hero);
_logger.log('Got ${heroes.length} heroes from the server.');
_backendService.getAll(Hero).then((heroes) {
_logger.log('Fetched ${heroes.length} heroes.');
this.heroes.addAll(heroes); // fill cache
});
return heroes;
}
}
// #enddocregion class

View File

@ -1,16 +1,11 @@
// #docregion
import 'dart:html';
import 'package:angular2/core.dart';
/// A service for logging messages of various types.
///
/// We could switch this implementation to use package:logging.
@Injectable()
// #docregion class
class Logger {
void log(Object msg) => window.console.log(msg);
void error(Object msg) => window.console.error(msg);
void warn(Object msg) => window.console.warn(msg);
}

View File

@ -0,0 +1,28 @@
import 'package:angular2/core.dart';
import 'sales_tax_service.dart';
import 'tax_rate_service.dart';
@Component(
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':false:'1.2-2' }}
<!-- would like to write currency:'USD':true:'1.2-2' but
currency as symbol is not currently supported; see
https://github.com/dart-lang/intl/issues/59 -->
</div>
''',
providers: const [SalesTaxService, TaxRateService])
class SalesTaxComponent {
SalesTaxService _salesTaxService;
SalesTaxComponent(this._salesTaxService) {}
num getTax(dynamic /* String | num */ value) =>
this._salesTaxService.getVAT(value);
}

View File

@ -0,0 +1,14 @@
import 'package:angular2/core.dart';
import 'tax_rate_service.dart';
@Injectable()
class SalesTaxService {
TaxRateService rateService;
SalesTaxService(this.rateService);
num getVAT(dynamic /* String | num */ value) =>
rateService.getRate('VAT') *
(value is num ? value : num.parse(value, (_) => 0));
}

View File

@ -0,0 +1,6 @@
import 'package:angular2/core.dart';
@Injectable()
class TaxRateService {
getRate(String rateName) => 0.10;
}

View File

@ -1,12 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>Intro to Angular 2</title>
<link rel="stylesheet" href="styles.css">
<script defer src="main.dart" type="application/dart"></script>
<script defer src="packages/browser/dart.js"></script>
</head>
<head>
<title>Architecture of Angular 2</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<script defer src="main.dart" type="application/dart"></script>
<script defer src="packages/browser/dart.js"></script>
</head>
<body>
<hero-list>Loading...</hero-list>
<my-app>Loading...</my-app>
</body>
</html>

View File

@ -1,13 +1,14 @@
// #docregion
import 'package:angular2/platform/browser.dart';
// #docregion import
import 'package:developer_guide_intro/app_component.dart';
// #enddocregion import
import 'package:developer_guide_intro/backend_service.dart';
import 'package:developer_guide_intro/hero_list_component.dart';
import 'package:developer_guide_intro/hero_service.dart';
import 'package:developer_guide_intro/logger_service.dart';
main() {
void main() {
// #docregion bootstrap
bootstrap(HeroListComponent, [BackendService, HeroService, Logger]);
bootstrap(AppComponent, [BackendService, HeroService, Logger]);
// #enddocregion bootstrap
}

View File

@ -1,63 +1,99 @@
/// <reference path='../_protractor/e2e.d.ts' />
'use strict';
describe('Architecture', function () {
let title = 'Hero List';
const nameSuffix = 'X';
beforeAll(function () {
browser.get('');
class Hero {
id: number;
name: string;
}
describe('Architecture', () => {
const expectedTitle = 'Architecture of Angular 2';
const expectedH2 = ['Hero List', 'Sales Tax Calculator'];
beforeAll(() => browser.get(''));
it(`has title '${expectedTitle}'`, () => {
expect(browser.getTitle()).toEqual(expectedTitle);
});
function itReset(name: string, func: () => any) {
it(name, function() {
browser.get('').then(func);
});
}
it(`should display correct title: ${title}`, function () {
expect(element(by.css('h2')).getText()).toEqual(title);
});
it('should display correct detail after selection', function() {
let detailView = element(by.css('hero-detail'));
expect(detailView.isPresent()).toBe(false);
// select the 2nd element
let selectEle = element.all(by.css('hero-list > div')).get(1);
selectEle.click().then(function() {
return selectEle.getText();
}).then(function(selectedHeroName) {
// works but too specific if we change the app
// expect(selectedHeroName).toEqual('Mr. Nice');
expect(detailView.isDisplayed()).toBe(true);
let detailTitleEle = element(by.css('hero-detail > h4'));
expect(detailTitleEle.getText()).toContain(selectedHeroName);
});
});
itReset('should display correct detail after modification', function() {
let detailView = element(by.css('hero-detail'));
expect(detailView.isPresent()).toBe(false);
// select the 2nd element
let selectEle = element.all(by.css('hero-list > div')).get(1);
selectEle.click().then(function () {
return selectEle.getText();
}).then(function (selectedHeroName) {
let detailTitleEle = element(by.css('hero-detail > h4'));
expect(detailTitleEle.getText()).toContain(selectedHeroName);
let heroNameEle = element.all(by.css('hero-detail input')).get(0);
// check that both the initial selected item and the detail title reflect changes
// made to the input box.
// heroNameEle.sendKeys('foo');
sendKeys(heroNameEle, 'foo');
expect(detailTitleEle.getText()).toContain('foo');
expect(selectEle.getText()).toContain('foo');
// getText on an input element always returns null
// http://stackoverflow.com/questions/20310442/how-to-gettext-on-an-input-in-protractor
// expect(heroNameEle.getText()).toEqual(selectedHeroName);
expect(heroNameEle.getAttribute('value')).toEqual(selectedHeroName + 'foo');
});
it(`has h2 '${expectedH2}'`, () => {
let h2 = element.all(by.css('h2')).map((elt) => elt.getText());
expect(h2).toEqual(expectedH2);
});
describe('Hero', heroTests);
describe('Salex tax', salesTaxTests);
});
function heroTests() {
const targetHero: Hero = { id: 2, name: 'Mr. Nice' };
it('has the right number of heroes', () => {
let page = getPageElts();
expect(page.heroes.count()).toEqual(3);
});
it('has no hero details initially', function () {
let page = getPageElts();
expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail');
});
it('shows selected hero details', async () => {
await element(by.cssContainingText('li', targetHero.name)).click();
let page = getPageElts();
let hero = await heroFromDetail(page.heroDetail);
expect(hero.id).toEqual(targetHero.id);
expect(hero.name).toEqual(targetHero.name);
});
it(`shows updated hero name in details`, async () => {
let input = element.all(by.css('input')).first();
await sendKeys(input, nameSuffix);
let page = getPageElts();
let hero = await heroFromDetail(page.heroDetail);
let newName = targetHero.name + nameSuffix;
expect(hero.id).toEqual(targetHero.id);
expect(hero.name).toEqual(newName);
});
}
function salesTaxTests() {
it('has no sales tax initially', function () {
let page = getPageElts();
expect(page.salesTaxDetail.isPresent()).toBeFalsy('no sales tax info');
});
it('shows sales tax', async function () {
let page = getPageElts();
await sendKeys(page.salesTaxAmountInput, '10');
// Note: due to Dart bug USD is shown instead of $
let re = /The sales tax is (\$|USD)1.00/;
expect(page.salesTaxDetail.getText()).toMatch(re);
});
}
// Helper functions
function getPageElts() {
return {
heroes: element.all(by.css('my-app li')),
heroDetail: element(by.css('my-app hero-detail')),
salesTaxAmountInput: element(by.css('my-app sales-tax input')),
salesTaxDetail: element(by.css('my-app sales-tax div'))
};
}
async function heroFromDetail(detail: protractor.ElementFinder): Promise<Hero> {
// Get hero id from the first <div>
let _id = await detail.all(by.css('div')).first().getText();
// Get name from the h2
let _name = await detail.element(by.css('h4')).getText();
return {
id: +_id.substr(_id.indexOf(' ') + 1),
name: _name.substr(0, _name.lastIndexOf(' '))
};
}

View File

@ -2,8 +2,8 @@
<h4>{{hero.name}} Detail</h4>
<div>Id: {{hero.id}}</div>
<div>Name:
<!-- #docregion ngModel -->
<input [(ngModel)]="hero.name">
<!-- #enddocregion ngModel -->
<!-- #docregion ngModel -->
<input [(ngModel)]="hero.name">
<!-- #enddocregion ngModel -->
</div>
<div>Power:<input [(ngModel)]="hero.power"></div>
<div>Power:<input [(ngModel)]="hero.power"></div>

View File

@ -1,12 +1,9 @@
<!--#docregion binding -->
<div>{{hero.name}}</div>
<li>{{hero.name}}</li>
<hero-detail [hero]="selectedHero"></hero-detail>
<div (click)="selectHero(hero)"></div>
<li (click)="selectHero(hero)"></li>
<!--#enddocregion binding -->
<!--#docregion structural -->
<div *ngFor="let hero of heroes"></div>
<li *ngFor="let hero of heroes"></li>
<hero-detail *ngIf="selectedHero"></hero-detail>
<!--#enddocregion structural -->

View File

@ -2,8 +2,10 @@
<h2>Hero List</h2>
<p><i>Pick a hero from the list</i></p>
<div *ngFor="let hero of heroes" (click)="selectHero(hero)">
{{hero.name}}
</div>
<ul>
<li *ngFor="let hero of heroes" (click)="selectHero(hero)">
{{hero.name}}
</li>
</ul>
<hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>

View File

@ -1,4 +1,3 @@
// #docplaster
import { Component, OnInit } from '@angular/core';
import { Hero } from './hero';
@ -6,35 +5,28 @@ import { HeroDetailComponent } from './hero-detail.component';
import { HeroService } from './hero.service';
// #docregion metadata
// #docregion providers
@Component({
// #enddocregion providers
selector: 'hero-list',
templateUrl: 'app/hero-list.component.html',
directives: [HeroDetailComponent],
// #docregion providers
// #docregion providers
providers: [HeroService]
// #enddocregion providers
})
// #enddocregion providers
// #enddocregion metadata
/*
// #docregion metadata, providers
export class HeroesComponent { ... }
// #enddocregion metadata, providers
*/
// #docregion class
export class HeroListComponent implements OnInit {
// #enddocregion metadata
heroes: Hero[];
selectedHero: Hero;
// #docregion ctor
// #docregion ctor
constructor(private service: HeroService) { }
// #enddocregion ctor
// #enddocregion ctor
ngOnInit() {
this.heroes = this.service.getHeroes();
}
selectHero(hero: Hero) { this.selectedHero = hero; }
// #docregion metadata
}
// #enddocregion class

View File

@ -9,11 +9,9 @@ import { Logger } from './logger.service';
export class HeroService {
private heroes: Hero[] = [];
// #docregion ctor
constructor(
private backend: BackendService,
private logger: Logger) { }
// #enddocregion ctor
getHeroes() {
this.backend.getAll(Hero).then( (heroes: Hero[]) => {
@ -23,4 +21,3 @@ export class HeroService {
return this.heroes;
}
}
// #enddocregion class

View File

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

View File

@ -1,14 +1,9 @@
// #docplaster
// #docregion
import { Component } from '@angular/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>
@ -19,24 +14,12 @@ import { TaxRateService } from './tax-rate.service';
{{ 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

@ -1,20 +1,14 @@
// #docregion
import { Injectable } from '@angular/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;
}
let amount = (typeof value === 'string') ?
parseFloat(value) : value;
return (amount || 0) * this.rateService.getRate('VAT');
}
}
// #enddocregion class

View File

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

View File

@ -4,7 +4,7 @@
<h3>Routed Movies</h3>
<nav>
<!-- #docregion router-link -->
<a [routerLink]="['Movies']">Movies</a>
<a [routerLink]="['/movies']">Movies</a>
<!-- #enddocregion router-link -->
</nav>
<router-outlet></router-outlet>

View File

@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from '@angular/router-deprecated';
import { ROUTER_DIRECTIVES } from '@angular/router';
import { MovieListComponent } from './movie-list.component';
import { MovieService } from './movie.service';
@ -12,11 +12,8 @@ import { StringSafeDatePipe } from './date.pipe';
styleUrls: ['app/app.component.css'],
directives: [MovieListComponent, ROUTER_DIRECTIVES],
pipes: [StringSafeDatePipe],
providers: [MovieService, ROUTER_PROVIDERS]
providers: [MovieService]
})
@RouteConfig([
{path: '/movies', name: 'Movies', component: MovieListComponent, useAsDefault: true}
])
export class AppComponent {
angularDocsUrl = 'https://angular.io/';

View File

@ -0,0 +1,13 @@
// #docregion
import { provideRouter, RouterConfig } from '@angular/router';
import { MovieListComponent } from './movie-list.component';
const routes: RouterConfig = [
{ path: '', redirectTo: '/movies', pathMatch: 'full' },
{ path: 'movies', component: MovieListComponent }
];
export const appRouterProviders = [
provideRouter(routes)
];

View File

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

View File

@ -1,6 +1,8 @@
// #docregion
import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
import { appRouterProviders } from './app.routes';
bootstrap(AppComponent);
bootstrap(AppComponent, [
appRouterProviders
]);

View File

@ -2,7 +2,6 @@
// #docplaster
// #docregion import
import { Component } from '@angular/core';
import { ROUTER_DIRECTIVES } from '@angular/router-deprecated';
// #enddocregion import
import { MovieService } from './movie.service';
import { IMovie } from './movie';

View File

@ -0,0 +1,7 @@
import { provideRouter, RouterConfig } from '@angular/router';
const routes: RouterConfig = [];
export const appRouterProviders = [
provideRouter(routes)
];

View File

@ -1,7 +1,7 @@
// #docregion
import { bootstrap } from '@angular/platform-browser-dynamic';
import { XHRBackend } from '@angular/http';
import { ROUTER_PROVIDERS } from '@angular/router-deprecated';
import { bootstrap } from '@angular/platform-browser-dynamic';
import { XHRBackend } from '@angular/http';
import { appRouterProviders } from './app.routes';
import { LocationStrategy,
HashLocationStrategy } from '@angular/common';
@ -13,7 +13,7 @@ import { AppComponent } from './app.component';
// #docregion bootstrap
bootstrap(AppComponent, [
ROUTER_PROVIDERS,
appRouterProviders,
{ provide: LocationStrategy, useClass: HashLocationStrategy },
{ provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server

View File

@ -1,42 +0,0 @@
// #docplaster
// #docregion
import { Component } from '@angular/core';
import { provideRouter, ROUTER_DIRECTIVES } from '@angular/router';
import { routes } from './app.routes';
// #docregion can-deactivate-guard
import { CanDeactivateGuard } from './interfaces';
// #enddocregion can-deactivate-guard
import { DialogService } from './dialog.service';
import { HeroService } from './heroes/hero.service';
// Add these symbols to override the `LocationStrategy`
import { LocationStrategy,
HashLocationStrategy } from '@angular/common';
@Component({
selector: 'my-app',
// #docregion template
template: `
<h1 class="title">Component Router</h1>
<nav>
<a [routerLink]="['/crisis-center']">Crisis Center</a>
<a [routerLink]="['/heroes']">Heroes</a>
</nav>
<router-outlet></router-outlet>
`,
// #enddocregion template
providers: [
HeroService,
DialogService,
provideRouter(routes),
CanDeactivateGuard,
{ provide: LocationStrategy,
useClass: HashLocationStrategy } // .../#/crisis-center/
],
directives: [ROUTER_DIRECTIVES]
})
export class AppComponent {
}

View File

@ -14,7 +14,7 @@ import { HeroDetailComponent } from './heroes/hero-detail.component';
// #docregion
// #docregion route-config
export const routes: RouterConfig = [
const routes: RouterConfig = [
// #docregion route-defs
{ path: 'crisis-center', component: CrisisCenterComponent },
{ path: 'heroes', component: HeroListComponent },

View File

@ -8,7 +8,7 @@ import { CrisisListComponent } from './crisis-list.component';
import { HeroListComponent } from './hero-list.component';
// #docregion route-config
export const routes: RouterConfig = [
const routes: RouterConfig = [
{ path: 'crisis-center', component: CrisisListComponent },
{ path: 'heroes', component: HeroListComponent }
];

View File

@ -28,6 +28,7 @@ import { AppComponent as S0704 } from '../07-04/app';
import { AppComponent as S0901 } from '../09-01/app';
const routes: RouterConfig = [
{ path: '', redirectTo: '/01-01', pathMatch: 'full' },
{ path: '01-01', component: S0101 },
{ path: '02-07', component: S0207 },
{ path: '02-08', component: S0208 },
@ -56,6 +57,6 @@ const routes: RouterConfig = [
{ path: '09-01', component: S0901 },
];
export const APP_ROUTER_PROVIDERS = [
export const appRouterProviders = [
provideRouter(routes)
];

View File

@ -4,12 +4,12 @@ import { HashLocationStrategy, LocationStrategy } from '@angular/common';
import { InMemoryBackendService, SEED_DATA } from 'angular2-in-memory-web-api';
import 'rxjs/add/operator/map';
import { APP_ROUTER_PROVIDERS } from './app.routes';
import { appRouterProviders } from './app.routes';
import { HeroData } from './hero-data';
import { AppComponent } from './app.component';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS,
appRouterProviders,
HTTP_PROVIDERS,
{ provide: LocationStrategy, useClass: HashLocationStrategy },
{ provide: XHRBackend, useClass: InMemoryBackendService },

View File

@ -5,13 +5,10 @@ import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import {
beforeEach, beforeEachProviders,
describe, ddescribe, xdescribe,
expect, it, iit, xit,
async, inject
} from '@angular/core/testing';
import { ComponentFixture, TestComponentBuilder } from '@angular/compiler/testing';
import { ComponentFixture, TestComponentBuilder } from '@angular/core/testing';
import { Hero, HeroService, MockHeroService } from './mock-hero.service';
@ -45,7 +42,7 @@ describe('AppComponent', () => {
it('can get title from template', () => {
fixture.detectChanges();
let titleEl = fixture.debugElement.query(By.css('h1')).nativeElement;
expect(titleEl).toHaveText(comp.title);
expect(titleEl.textContent).toContain(comp.title);
});
it('can get RouterLinks from template', () => {

View File

@ -19,13 +19,11 @@ import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import {
beforeEach, beforeEachProviders,
describe, ddescribe, xdescribe,
expect, it, iit, xit,
addProviders,
async, inject
} from '@angular/core/testing';
import { ComponentFixture, TestComponentBuilder } from '@angular/compiler/testing';
import { ComponentFixture, TestComponentBuilder } from '@angular/core/testing';
import { ViewMetadata } from '@angular/core';
import { Observable } from 'rxjs/Rx';
@ -143,20 +141,20 @@ xdescribe('async & inject testing errors', () => {
restoreJasmineIt();
}, 10000);
describe('using beforeEachProviders', () => {
beforeEachProviders(() => [{ provide: FancyService, useValue: new FancyService() }]);
describe('using addProviders', () => {
addProviders([{ provide: FancyService, useValue: new FancyService() }]);
beforeEach(
inject([FancyService], (service: FancyService) => { expect(service.value).toEqual('real value'); }));
describe('nested beforeEachProviders', () => {
describe('nested addProviders', () => {
it('should fail when the injector has already been used', () => {
patchJasmineBeforeEach();
expect(() => {
beforeEachProviders(() => [{ provide: FancyService, useValue: new FancyService() }]);
addProviders([{ provide: FancyService, useValue: new FancyService() }]);
})
.toThrowError('beforeEachProviders was called after the injector had been used ' +
.toThrowError('addProviders was called after the injector had been used ' +
'in a beforeEach or it block. This invalidates the test injector');
restoreJasmineBeforeEach();
});

View File

@ -1,7 +1,7 @@
// Based on https://github.com/angular/angular/blob/master/modules/angular2/test/testing/testing_public_spec.ts
/* tslint:disable */
import {
BadTemplateUrl, ButtonComp,
ButtonComp,
ChildChildComp, ChildComp, ChildWithChildComp,
ExternalTemplateComp,
FancyService, MockFancyService,
@ -16,14 +16,12 @@ import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import {
beforeEach, beforeEachProviders,
describe, ddescribe, xdescribe,
expect, it, iit, xit,
async, inject,
addProviders,
inject, async,
fakeAsync, tick, withProviders
} from '@angular/core/testing';
import { ComponentFixture, TestComponentBuilder } from '@angular/compiler/testing';
import { ComponentFixture, TestComponentBuilder } from '@angular/core/testing';
import { ViewMetadata } from '@angular/core';
@ -31,47 +29,6 @@ import { Observable } from 'rxjs/Rx';
//////// SPECS /////////////
/// Verify can use Angular testing's DOM abstraction to access DOM
describe('angular2 jasmine matchers', () => {
describe('toHaveCssClass', () => {
it('should assert that the CSS class is present', () => {
let el = document.createElement('div');
el.classList.add('bombasto');
expect(el).toHaveCssClass('bombasto');
});
it('should assert that the CSS class is not present', () => {
let el = document.createElement('div');
el.classList.add('bombasto');
expect(el).not.toHaveCssClass('fatias');
});
});
describe('toHaveCssStyle', () => {
it('should assert that the CSS style is present', () => {
let el = document.createElement('div');
expect(el).not.toHaveCssStyle('width');
el.style.setProperty('width', '100px');
expect(el).toHaveCssStyle('width');
});
it('should assert that the styles are matched against the element', () => {
let el = document.createElement('div');
expect(el).not.toHaveCssStyle({width: '100px', height: '555px'});
el.style.setProperty('width', '100px');
expect(el).toHaveCssStyle({width: '100px'});
expect(el).not.toHaveCssStyle({width: '100px', height: '555px'});
el.style.setProperty('height', '555px');
expect(el).toHaveCssStyle({height: '555px'});
expect(el).toHaveCssStyle({width: '100px', height: '555px'});
});
});
});
describe('using the async helper', () => {
let actuallyDone = false;
@ -101,7 +58,7 @@ describe('using the async helper', () => {
p.catch(() => { actuallyDone = true; });
}));
it('should run async test with successful Observable', async(() => {
xit('should run async test with successful Observable', async(() => {
let source = Observable.of(true).delay(10);
source.subscribe(
val => {},
@ -114,9 +71,11 @@ describe('using the async helper', () => {
describe('using the test injector with the inject helper', () => {
describe('setting up Providers with FancyService', () => {
beforeEachProviders(() => [
{ provide: FancyService, useValue: new FancyService() }
]);
beforeEach(() => {
addProviders([
{ provide: FancyService, useValue: new FancyService() }
]);
});
it('should use FancyService',
inject([FancyService], (service: FancyService) => {
@ -142,7 +101,7 @@ describe('using the test injector with the inject helper', () => {
);
})));
it('test should wait for FancyService.getObservableDelayValue',
xit('test should wait for FancyService.getObservableDelayValue',
async(inject([FancyService], (service: FancyService) => {
service.getObservableDelayValue().subscribe(
value => { expect(value).toEqual('observable delay value'); }
@ -197,7 +156,7 @@ describe('test component builder', function() {
tcb.createAsync(ChildComp).then(fixture => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('Original Child');
expect(fixture.nativeElement.textContent).toContain('Original Child');
});
})));
@ -206,11 +165,11 @@ describe('test component builder', function() {
tcb.createAsync(MyIfComp).then(fixture => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('MyIf()');
expect(fixture.nativeElement.textContent).toContain('MyIf()');
fixture.debugElement.componentInstance.showMore = true;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('MyIf(More)');
expect(fixture.nativeElement.textContent).toContain('MyIf(More)');
});
})));
@ -262,7 +221,7 @@ describe('test component builder', function() {
.createAsync(MockChildComp)
.then(fixture => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('Mock');
expect(fixture.nativeElement.textContent).toContain('Mock');
});
})));
@ -276,7 +235,7 @@ describe('test component builder', function() {
.createAsync(ChildComp)
.then(fixture => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('Modified Child');
expect(fixture.nativeElement.textContent).toContain('Modified Child');
});
})));
@ -288,7 +247,7 @@ describe('test component builder', function() {
.createAsync(ParentComp)
.then(fixture => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('Parent(Mock)');
expect(fixture.nativeElement.textContent).toContain('Parent(Mock)');
});
})));
@ -302,8 +261,8 @@ describe('test component builder', function() {
.createAsync(ParentComp)
.then(fixture => {
fixture.detectChanges();
expect(fixture.nativeElement)
.toHaveText('Parent(Original Child(ChildChild Mock))');
expect(fixture.nativeElement.textContent)
.toContain('Parent(Original Child(ChildChild Mock))');
});
})));
@ -318,8 +277,8 @@ describe('test component builder', function() {
.createAsync(TestProvidersComp)
.then(fixture => {
fixture.detectChanges();
expect(fixture.nativeElement)
.toHaveText('injected value: mocked out value');
expect(fixture.nativeElement.textContent)
.toContain('injected value: mocked out value');
});
})));
@ -333,8 +292,8 @@ describe('test component builder', function() {
.createAsync(TestViewProvidersComp)
.then(fixture => {
fixture.detectChanges();
expect(fixture.nativeElement)
.toHaveText('injected value: mocked out value');
expect(fixture.nativeElement.textContent)
.toContain('injected value: mocked out value');
});
})));
@ -344,8 +303,8 @@ describe('test component builder', function() {
tcb.createAsync(ExternalTemplateComp)
.then(fixture => {
fixture.detectChanges();
expect(fixture.nativeElement)
.toHaveText('from external template\n');
expect(fixture.nativeElement.textContent)
.toContain('from external template\n');
});
})), 10000); // Long timeout because this test makes an actual XHR.

View File

@ -4,13 +4,11 @@ import { DashboardComponent } from './dashboard.component';
import { By } from '@angular/platform-browser';
import {
beforeEach, beforeEachProviders,
describe, ddescribe, xdescribe,
expect, it, iit, xit,
addProviders,
async, inject
} from '@angular/core/testing';
import { ComponentFixture, TestComponentBuilder } from '@angular/compiler/testing';
import { ComponentFixture, TestComponentBuilder } from '@angular/core/testing';
import { Hero, HeroService, MockHeroService } from './mock-hero.service';
import { Router, MockRouter } from './mock-router';
@ -70,13 +68,13 @@ describe('DashboardComponent', () => {
let comp: DashboardComponent;
let mockHeroService: MockHeroService;
beforeEachProviders(() => {
beforeEach(() => {
mockHeroService = new MockHeroService();
return [
addProviders([
{ provide: Router, useClass: MockRouter},
{ provide: MockRouter, useExisting: Router},
{ provide: HeroService, useValue: mockHeroService }
];
]);
});
it('can instantiate it',
@ -138,8 +136,8 @@ describe('DashboardComponent', () => {
expect(heroNames.length).toEqual(4, 'should display 4 heroes');
// the 4th displayed hero should be the 5th mock hero
expect(heroNames[3].nativeElement)
.toHaveText(mockHeroService.mockHeroes[4].name);
expect(heroNames[3].nativeElement.textContent)
.toContain(mockHeroService.mockHeroes[4].name);
});
});

View File

@ -1,9 +0,0 @@
// See https://github.com/angular/angular/issues/9017
import { expect as expectCore } from '@angular/core/testing';
import { NgMatchers } from '@angular/platform-browser/testing';
export function expect(spy: Function): NgMatchers;
export function expect(actual: any): NgMatchers;
export function expect(actual: any): NgMatchers {
return expectCore(actual) as NgMatchers;
}

View File

@ -1,12 +1,10 @@
/* tslint:disable:no-unused-variable */
import {
beforeEach, beforeEachProviders,
describe, ddescribe, xdescribe,
expect, it, iit, xit,
addProviders,
async, inject, withProviders
} from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { TestComponentBuilder } from '@angular/core/testing';
import {
MockBackend,
@ -42,10 +40,12 @@ const makeResponseData = (data: {}) => {return { data }; };
//////// SPECS /////////////
describe('Http-HeroService (mockBackend)', () => {
beforeEachProviders(() => [
HTTP_PROVIDERS,
{ provide: XHRBackend, useClass: MockBackend }
]);
beforeEach(() => {
addProviders([
HTTP_PROVIDERS,
{ provide: XHRBackend, useClass: MockBackend }
]);
});
it('can instantiate service when inject service',
withProviders(() => [HeroService])

View File

@ -0,0 +1,3 @@
{
"startPath": "unit-tests.html"
}

View File

@ -1,7 +1,7 @@
// #docregion
import { Hero } from './hero';
export var HEROES: Hero[] = [
export const HEROES: Hero[] = [
{id: 11, name: 'Mr. Nice'},
{id: 12, name: 'Narco'},
{id: 13, name: 'Bombasto'},

View File

@ -6,7 +6,7 @@ import { HeroesComponent } from './heroes.component';
import { HeroDetailComponent } from './hero-detail.component';
// #enddocregion hero-detail-import
export const routes: RouterConfig = [
const routes: RouterConfig = [
// #docregion redirect-route
{
path: '',
@ -32,6 +32,6 @@ export const routes: RouterConfig = [
}
];
export const APP_ROUTER_PROVIDERS = [
export const appRouterProviders = [
provideRouter(routes)
];

View File

@ -9,6 +9,6 @@ const routes: RouterConfig = [
}
];
export const APP_ROUTER_PROVIDERS = [
export const appRouterProviders = [
provideRouter(routes)
];

View File

@ -7,7 +7,7 @@ import { HeroesComponent } from './heroes.component';
import { HeroDetailComponent } from './hero-detail.component';
// #enddocregion hero-detail-import
export const routes: RouterConfig = [
const routes: RouterConfig = [
{
path: '',
redirectTo: '/dashboard',
@ -27,6 +27,6 @@ export const routes: RouterConfig = [
}
];
export const APP_ROUTER_PROVIDERS = [
export const appRouterProviders = [
provideRouter(routes)
];

View File

@ -2,8 +2,8 @@
import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
import { APP_ROUTER_PROVIDERS } from './app.routes';
import { appRouterProviders } from './app.routes';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS
appRouterProviders
]);

View File

@ -5,7 +5,7 @@ import { DashboardComponent } from './dashboard.component';
import { HeroesComponent } from './heroes.component';
import { HeroDetailComponent } from './hero-detail.component';
export const routes: RouterConfig = [
const routes: RouterConfig = [
{
path: '',
redirectTo: '/dashboard',
@ -25,6 +25,6 @@ export const routes: RouterConfig = [
}
];
export const APP_ROUTER_PROVIDERS = [
export const appRouterProviders = [
provideRouter(routes)
];

View File

@ -12,20 +12,20 @@ import { bootstrap } from '@angular/platform-browser-dynamic';
import { HTTP_PROVIDERS } from '@angular/http';
import { AppComponent } from './app.component';
import { APP_ROUTER_PROVIDERS } from './app.routes';
import { appRouterProviders } from './app.routes';
// #enddocregion v1, final
/*
// #docregion v1
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS,
appRouterProviders,
HTTP_PROVIDERS
]);
// #enddocregion v1
*/
// #docregion final
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS,
appRouterProviders,
HTTP_PROVIDERS,
{ provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server
{ provide: SEED_DATA, useClass: InMemoryDataService } // in-mem server data

View File

@ -24,6 +24,7 @@
"zone.js": "0.6.12"
},
"devDependencies": {
"angular2-template-loader": "^0.4.0",
"css-loader": "^0.23.1",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",

View File

@ -0,0 +1 @@
!= partial("../../../_includes/_ts-temp")

View File

@ -0,0 +1 @@
!= partial("../../../_includes/_ts-temp")

View File

@ -1,451 +1,72 @@
include ../_util-fns
extends ../../../ts/latest/guide/architecture.jade
block includes
include ../_util-fns
- var _library_module = 'library'
- var _at_angular = 'angular2'
:marked
Angular 2 is a framework to help us build client applications in HTML and
either JavaScript or a language (like Dart or TypeScript) that compiles to JavaScript.
Angular 2 for Dart is published as the `angular2` package, which
(like many other Dart packages) is available via the Pub tool.
With Angular, 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 for Dart application rests on seven main building blocks:
1. [Components](#component)
1. [Templates](#template)
1. [Metadata](#metadata)
1. [Data binding](#data-binding)
1. [Directives](#directive)
1. [Services](#service)
1. [Dependency injection](#dependency-injection)
figure
img(src="/resources/images/devguide/architecture/overview.png" alt="overview" style="margin-left:-40px;" width="700")
:marked
Learn these seven and we're on our way.
.l-main-section
<a id="component"></a>
:marked
## Components
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*.
A set of navigation links, a list of heroes, a 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 clicks to choose a hero from that list.
The component might be a class like this:
+makeExample('architecture/dart/lib/hero_list_component.dart', 'class', 'lib/hero_list_component.dart')
: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.
<!-- PENDING: What was that supposed to link to? -->
.l-sub-section
block angular-parts
:marked
We may wonder who is calling the component's 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.
Angular 2 for Dart is published as the `angular2` package, which
(like many other Dart packages) is available via the Pub tool.
.l-main-section
<a id="template"></a>
:marked
## Templates
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.
block modules-in-dart
.callout.is-helpful
header Dart difference: Modules are compilation units or packages
:marked
In this guide, the term _module_ refers to a Dart compilation unit, such
as a library, or a package. (If a Dart file has no `library` or `part`
directive, then that file itself is a library and thus a compilation
unit.) For more information about compilation units, see
the chapter on "Libraries and Scripts" in the
[Dart Language Specification](https://www.dartlang.org/docs/spec/).
A template looks like regular HTML much of the time ... and then it gets a bit strange. Here is a
template for our `HeroListComponent`:
+makeExample('architecture/dart/lib/hero_list_component.html', null, 'lib/hero_list_component.html')
:marked
This template features typical HTML elements like `<h2>` and `<div>`.
But what are `*ngFor`, <code>{&zwnj;{hero.name}}</code>, `(click)`, `[hero]`, and `<hero-detail>`?
They're examples of Angular's template syntax. <!-- TODO: link to template-syntax.html -->
We'll grow accustomed to that syntax and may even learn to love it.
block modules-are-optional
//- N/A
Take a look at the last line,
which has the `<hero-detail>` tag.
That tag adds a custom element representing a component we haven't seen yet,
a `HeroDetailComponent`.
block export-qualifier
.callout.is-helpful
header Dart difference: Public names are exported by default
:marked
Contrary to TypeScript, a Dart library always exports all names and
declarations in its **public** namespace, making explicit `export`
qualifiers unnecessary.
When we say that a module _exports_ a declaration, we mean that the
declaration is _public_. For more details about name spaces and export
statements, see the section on "Exports" in the
[Dart Language Specification](https://www.dartlang.org/docs/spec/).
The `HeroDetailComponent` is a *different* component than the `HeroListComponent` we've seen.
The `HeroDetailComponent` (code not shown) presents facts about a particular hero, the
hero that the user selects from the list presented by the `HeroListComponent`.
The `HeroDetailComponent` is a **child** of the `HeroListComponent`.
block ts-import
//- N/A
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 native HTML elements.
We can and _will_ mix our custom components with native HTML in the same layouts.
In this manner we'll compose complex component trees to build out our richly featured application.
<br clear="all">
.l-main-section
<a id="metadata"></a>
:marked
## 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 at the code](#component-code) for `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.
In Dart, we attach metadata by using an **annotation**.
Here's some metadata for `HeroListComponent`:
+makeExample('architecture/dart/lib/hero_list_component.dart', 'metadata', 'lib/hero_list_component.dart')
:marked
Here we see the `@Component` annotation, which (no surprise) identifies the class
immediately below it as a component class.
Annotations often have configuration parameters.
The `@Component` annotation takes parameters to provide the
information Angular needs to create and present the component and its view.
Here we see a few of the possible `@Component` parameters:
* `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.
For example, if an app's HTML contains `<hero-list></hero-list>`, then
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 later.
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
At runtime, Angular discovers the metadata specified by the `@Component`
annotation. That's how Angular learns how to do "the right thing".
The template, metadata, and component together describe the view.
We apply other metadata annotations in a similar fashion to guide Angular behavior.
`@Injectable`, `@Input`, `@Output`, and `@RouterConfig` are a few of the more popular annotations
we'll master as our Angular knowledge grows.
<br clear="all">
:marked
The architectural takeaway 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 any 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/dart/lib/hero_list_component_1.html', 'binding')(format=".")
:marked
* The <code>{&zwnj;{hero.name}}</code> [interpolation](displaying-data.html#interpolation)
displays the component's `hero.name` property value within the `<div>` tags.
* The `[hero]` property binding <!-- TODO: link to template-syntax.html#property-binding-->
passes the value of `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 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:
+makeExample('architecture/dart/lib/hero_detail_component.html', 'ng-model', 'lib/hero_detail_component.html (excerpt)')(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.
<!-- PENDING: clarify what "depth-first from the root" really means,
or reassure that they'll learn it soon. -->
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
Data binding is also important for communication between parent and child components.
<br clear="all">
.l-main-section
<a id="directive"></a>
:marked
## Directives
figure
img(src="/resources/images/devguide/architecture/directive.png" alt="Parent child" style="float:left; width:150px; margin-left:-40px;margin-right:10px" )
:marked
Angular templates are *dynamic*. When Angular renders them, it transforms the DOM
according to the instructions given by **directives**.
A directive is a class with directive metadata. In Dart we apply the `@Directive` annotation
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*;
a `@Component` annotation is actually a `@Directive` annotation extended with template-oriented features.
.l-sub-section
block angular-library-modules
:marked
While **a component is technically a directive**,
components are so distinctive and central to Angular applications that we chose
to separate components from directives in this architectural overview.
:marked
Two *other* kinds of directives exist: _structural_ and _attribute_ directives.
Angular ships as a collection of libraries within the
[**angular2**](https://pub.dartlang.org/packages/angular2) package.
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.
block angular-imports
+makeExcerpt('app/app.component.ts', 'import')
**Structural** directives alter layout by adding, removing, and replacing elements in DOM.
Our [example](#template) template uses two built-in structural directives:
+makeExample('architecture/dart/lib/hero_list_component_1.html', 'structural')(format=".")
:marked
* [`*ngFor`](displaying-data.html#ng-for) tells Angular to stamp out one `<div>` per hero in the `heroes` list.
* [`*ngIf`](displaying-data.html#ng-if) includes the `HeroDetail` component only if a selected hero exists.
.l-sub-section
block ts-decorator
:marked
In Dart, **the only value that is true is the boolean value `true`**; all
other values are false. JavaScript and TypeScript, in contrast, treat values
such as 1 and most non-null objects as true. For this reason, the JavaScript
and TypeScript versions of this app can use just `selectedHero` as the value
of the `*ngIf` expression. The Dart version must use a boolean operator such
as `!=` instead.
Annotations often have configuration parameters.
The `@Component` annotation takes parameters to provide the
information Angular needs to create and present the component and its view.
:marked
**Attribute** directives alter the appearance or behavior of an existing element.
In templates they look like regular HTML attributes, hence the name.
Here are a few of the possible `@Component` parameters:
The `ngModel` directive, which implements two-way data binding, is
an example of an attribute directive. `ngModel` modifies the behavior of
an existing element (typically an `<input>`)
by setting its display value property and responding to change events.
+makeExample('architecture/dart/lib/hero_detail_component.html', 'ng-model')(format=".")
:marked
Angular ships with a small number of other directives that either alter the layout structure
(for example, `ngSwitch`) <!-- TODO: link to template-syntax.html#ng-switch -->
or modify aspects of DOM elements and components
(for example, `ngStyle` and `ngClass`).
<!-- PENDING: link to template-syntax.html#ng-style template-syntax.html#ng-class-->
Of course, we can also write our own directives. Components such as
`HeroListComponent` are one kind of custom directive.
<!-- PENDING: link to where to learn more about other kinds! -->
.l-main-section
<a id="service"></a>
:marked
## Services
figure
img(src="/resources/images/devguide/architecture/service.png" alt="Service" style="float:left; margin-left:-40px;margin-right:10px" )
:marked
_Services_ 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, and no place to register a service.
Yet services are fundamental to any Angular application. Our components are big consumers of services.
We prefer our component classes lean. Our components don't fetch data from the server,
they don't validate user input, and they don't log directly to 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 properties and methods for data binding.
It delegates everything nontrivial to services.
Angular doesn't *enforce* these principles.
It won't complain if we 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
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 a `HeroService`:
+makeExample('architecture/dart/lib/hero_list_component.dart', 'ctor', 'lib/hero_list_component.dart (excerpt)')(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/dart/web/main.dart', 'bootstrap', 'web/main.dart (excerpt)')(format='.')
:marked
Alternatively, we might register at a component level:
+makeExample('architecture/dart/lib/hero_list_component.dart', 'providers', 'lib/hero_list_component.dart (excerpt)')(format='.')
:marked
Registering at a component level means we get a new instance of the
service with each new instance of that component.
<!-- We've vastly oversimplified dependency injection for this overview.
The full story is in the [Dependency Injection](dependency-injection.html) chapter. -->
Points to remember about dependency injection:
* Dependency injection is wired into the Angular framework and used everywhere.
* 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
## Other stuff
We've learned just a bit about the seven main building blocks of an Angular application:
1. [Components](#component)
1. [Templates](#template)
1. [Metadata](#metadata)
1. [Data binding](#data-binding)
1. [Directives](#directive)
1. [Services](#service)
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.
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 raises 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:** Services that transform values for display.
We can put pipes in our templates to improve the user experience. Consider
this `currency` pipe expression:
<div style="margin-left:40px">
code-example(language="javascript" linenumbers=".").
price | currency:'USD':true'
</div>
:marked
>It displays a price of "42.33" as `$42.33`.
>**Testing:** Angular provides a
[testing library](https://pub.dartlang.org/packages/angular2_testing)
to run unit tests on our application parts as they interact with the Angular framework.
block dart-bool
.callout.is-helpful
header Dart difference: Only true is true
:marked
In Dart, **the only value that is true is the boolean value `true`**; all
other values are false. JavaScript and TypeScript, in contrast, treat values
such as 1 and most non-null objects as true. For this reason, the JavaScript
and TypeScript versions of this app can use just `selectedHero` as the value
of the `*ngIf` expression. The Dart version must use a boolean operator such
as `!=` instead.

View File

@ -19,7 +19,7 @@ block css-import-url
.alert.is-important
:marked
URLs are currently not interpreted in this way, see
[issue 8518](href="https://github.com/angular/angular/issues/8518").
[issue 8518](https://github.com/angular/angular/issues/8518).
Until this issue is fixed, absolute package-reference style URLs must
be given as is illustrated below.

View File

@ -101,7 +101,7 @@ block dart-map-alternative
As an alternative to using a configuration `Map`, we can define
a custom configuration class:
+makeExample('dependency-injection/ts/app/app.config.ts','config-alt','app/app-config.ts (alternative config)')(format='.')
+makeExample('lib/app_config.dart (alternative config)','config-alt')
:marked
Defining a configuration class has a few benefits. One key benefit

View File

@ -0,0 +1 @@
!= partial("../../../_includes/_ts-temp")

View File

@ -517,7 +517,7 @@ figure.image-display
Recall from the previous section that `ngControl` registered this input box with the
`NgForm` directive as "name".
We didn't add the **[`NgForm`](../api/common/NgForm-directive.html) directive*
We didn't add the **[`NgForm`](../api/common/index/NgForm-directive.html) directive*
explicitly. Angular added it surreptitiously, wrapping it around the `<form>` element.
The `NgForm` directive supplements the `<form>` element with additional features.

View File

@ -1 +1 @@
!= partial("../glossary")
include ../glossary

View File

@ -33,7 +33,7 @@ block http-providers
block getheroes-and-addhero
:marked
The hero service `getHeroes()` and `addHero()` asynchronous methods return the
[`Future`](https://api.dartlang.org/stable/1.16.0/dart-async/Future-class.html)
[`Future`](https://api.dartlang.org/stable/dart-async/Future-class.html)
values of the current hero list and the newly added hero,
respectively. The hero list component methods of the same name specifying
the actions to be taken when the asynchronous method calls succeed or fail.

View File

@ -5,7 +5,7 @@ block includes
- var _JavaScript = 'Dart';
- var __chaining_op = '<code>;</code>';
- var __new_op = '<code>new</code> or <code>const</code>';
- var mapApiRef = 'https://api.dartlang.org/stable/1.16.0/dart-core/Map-class.html';
- var mapApiRef = 'https://api.dartlang.org/stable/dart-core/Map-class.html';
- var __objectAsMap = '<b><a href="' + mapApiRef + '">Map</a></b>'
block notable-differences
@ -69,7 +69,7 @@ block style-property-name-dart-diff
and `setProperty()`. Hence, we recommend only using dash-case for style
property names.
[CssSD]: https://api.dartlang.org/stable/1.16.1/dart-html/CssStyleDeclaration-class.html
[CssSD]: https://api.dartlang.org/stable/dart-html/CssStyleDeclaration-class.html
block dart-no-truthy-falsey

View File

@ -17,8 +17,8 @@ block setup-tooling
You can also download [Dart plugins for other IDEs and editors][DT].
[WS]: https://confluence.jetbrains.com/display/WI/Getting+started+with+Dart
[DT]: https://www.dartlang.org/tools
[pub]: https://www.dartlang.org/tools/pub
[DT]: https://www.dartlang.org/tools/
[pub]: https://www.dartlang.org/tools/pub/
block download-source
// exclude this section from Dart

View File

@ -132,9 +132,6 @@ code-example(language="bash").
### Add a base tag
// Our Tour of Heroes needs routing,
// so we load the library in the `index.html` in a script tag immediately *after* the angular script itself.
//+makeExample('toh-5/dart/web/index.html', 'router', 'index.html (router)')(format=".")
:marked
First, edit `index.html` and add `<base href="/">` at the top of the `<head>` section.
+makeExample('toh-5/dart/web/index.html', 'base-href', 'index.html (base href)')(format=".")
@ -442,7 +439,7 @@ code-example(format='').
:marked
Going back too far could take us out of the application.
That's acceptable in a demo. We'd guard against it in a real application,
perhaps with the [*routerCanDeactivate* hook](../api/router/CanDeactivate-interface.html).
perhaps with the [*routerCanDeactivate* hook](../api/router/index/CanDeactivate-interface.html).
:marked
Then we wire this method with an event binding to a *Back* button that we add to the bottom of the component template.
+makeExample('toh-5/dart/lib/hero_detail_component.html', 'back-button')(format=".")

View File

@ -0,0 +1 @@
!= partial("../../../_includes/_ts-temp")

View File

@ -0,0 +1 @@
!= partial("../../../_includes/_ts-temp")

View File

@ -493,7 +493,7 @@ figure.image-display
:marked
### The NgForm directive
We just set a template local variable with the value of an `NgForm` directive.
Why did that work? We didn't add the **[`NgForm`](../api/common/NgForm-directive.html) directive** explicitly.
Why did that work? We didn't add the **[`NgForm`](../api/common/index/NgForm-directive.html) directive** explicitly.
Angular added it surreptitiously, wrapping it around the `<form>` element

View File

@ -491,7 +491,7 @@ figure.image-display
.l-sub-section
:marked
Why "ngModel"?
A directive's [exportAs](../api/core/DirectiveMetadata-class.html#!#exportAs) property
A directive's [exportAs](../api/core/index/DirectiveMetadata-class.html#!#exportAs) property
tells Angular how to link the reference variable to the directive.
We set `name` to `ngModel` because the `ngModel` directive's `exportAs` property happens to be "ngModel".
@ -503,7 +503,7 @@ figure.image-display
:marked
### The NgForm directive
We just set a template local variable with the value of an `NgForm` directive.
Why did that work? We didn't add the **[`NgForm`](../api/common/NgForm-directive.html) directive** explicitly.
Why did that work? We didn't add the **[`NgForm`](../api/common/index/NgForm-directive.html) directive** explicitly.
Angular added it surreptitiously, wrapping it around the `<form>` element

View File

@ -227,7 +227,7 @@ table(width="100%")
### 引导
+makeExample('cb-a1-a2-quick-reference/ts/app/main.ts')(format="." )
+makeExample('cb-a1-a2-quick-reference/ts/app/main.1.ts')(format="." )
:marked
Angular&nbsp;2 does not have a bootstrap directive.
We always launch the app in code by explicitly calling a bootstrap function

View File

@ -58,7 +58,7 @@ code-example(format='')
## 使用*Title*服务
Fortunately, Angular 2 bridges the gap by providing a `Title` service as part of the *Browser platform*.
The [Title](../api/platform/browser/Title-class.html) service is a simple class that provides an API
The [Title](../api/platform-browser/index/Title-class.html) service is a simple class that provides an API
for getting and setting the current HTML document title:
幸运的是Angular 2在*浏览器平台*的包中,提供了一个`Title`服务,弥补了这个差别。

View File

@ -73,7 +73,8 @@ include _util-fns
Imagine three modules in a `heroes` folder:
设想在`heroes`目录下有三个模块:
code-example(format='').
code-example.
// heroes/hero.component.ts
export class HeroComponent {}
@ -86,7 +87,8 @@ include _util-fns
Without a barrel, a consumer would need three import statements:
假如没有封装桶消费者就需要三条import语句
code-example(format='').
code-example.
import { HeroComponent } from '../heroes/hero.component.ts';
import { Hero } from '../heroes/hero.model.ts';
import { HeroService } from '../heroes/hero.service.ts';
@ -94,7 +96,8 @@ include _util-fns
We can add a barrel to the `heroes` folder (called `index` by convention) that exports all of these items:
在`heroes`目录下添加一个封装桶(按规约叫做`index`),它导出所有这三条:
code-example(format='').
code-example.
export * from './hero.model.ts'; // re-export all of its exports
export * from './hero.service.ts'; // re-export all of its exports
export { HeroComponent } from './hero.component.ts'; // re-export the named thing
@ -102,7 +105,8 @@ include _util-fns
Now a consumer can import what it needs from the barrel.
现在,消费者就就可以从这个封装桶中导入它需要的东西了。
code-example(format='').
code-example.
import { Hero, HeroService } from '../heroes'; // index is implied
:marked
The Angular [scoped packages](#scoped-package) each have a barrel named `index`.
@ -113,7 +117,8 @@ include _util-fns
That's why we can write this:
这就是为什么可以这样写的原因:
+makeExample('../docs/_fragments/quickstart/ts/app/app.component.ts', 'import')(format=".")
+makeExcerpt('quickstart/ts/app/app.component.ts', 'import', '')
// #docregion b-c
:marked
@ -862,8 +867,8 @@ include _util-fns
使用和导入*普通*包相同的方式导入范围化包。
从消费者的视角看唯一的不同是那些包的名字是用Angular的*范围名*`@angular`开头儿的。
+makeExample('../docs/_fragments/architecture/ts/app/app.component.ts', 'import')(format=".")
// #docregion n-s
+makeExcerpt('architecture/ts/app/app.component.ts', 'import', '')
// #docregion n-s-2
:marked
## Structural Directive

File diff suppressed because it is too large Load Diff

View File

@ -806,10 +806,27 @@ code-example(format="nocode").
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-1')
p
| This is actually a short-hand expression for a provider registration
block canonical-provider-expr
| &nbsp;using a <i>provider</i> object literal with two properties:
:marked
This is actually a short-hand expression for a provider registration
这实际上是注册提供商的一种简写表达式。
<span if-docs="ts">
using a _provider_ object literal with two properties:
</span>
<span if-docs="ts">
使用一个拥有两个属性的_provider_对象
</span>
<span if-docs="dart">
that creates a new instance of the
[Provider](../api/core/index/Provider-class.html) class:
</span>
<span if-docs="dart">
创建[Provider](../api/core/index/Provider-class.html)类的一个实例:
</span>
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-3')

View File

@ -380,7 +380,7 @@ figure.image-display
We'll talk about `NgForm` [later in the chapter](#ngForm).
The `ngControl` *attribute* in our template actually maps to the
[NgControlName](../api/common/NgControlName-directive.html) directive.
[NgControlName](../api/common/index/NgControlName-directive.html) directive.
There is also a `NgControl` *abstract* directive which is *not the same thing*.
We often ignore this technical distinction and refer to `NgControlName` more conveniently (albeit incorrectly) as the *NgControl* directive.
@ -483,7 +483,7 @@ figure.image-display
.l-sub-section
:marked
Why "ngForm"?
A directive's [exportAs](../api/core/DirectiveMetadata-class.html#!#exportAs) property
A directive's [exportAs](../api/core/index/DirectiveMetadata-class.html#!#exportAs) property
tells Angular how to link the reference variable to the directive.
We set `name` to `ngForm` because the `NgControlName` directive's `exportAs` property happens to be "ngForm".
@ -589,7 +589,7 @@ figure.image-display
.l-sub-section
:marked
### The NgForm directive
What `NgForm` directive? We didn't add an [NgForm](../api/common/NgForm-directive.html) directive!
What `NgForm` directive? We didn't add an [NgForm](../api/common/index/NgForm-directive.html) directive!
Angular did. Angular creates and attaches an `NgForm` directive to the `<form>` tag automatically.

View File

@ -1064,7 +1064,7 @@ figure.image-display
### NgForm指令
What `NgForm` directive? We didn't add an [NgForm](../api/common/NgForm-directive.html) directive!
What `NgForm` directive? We didn't add an [NgForm](../api/common/index/NgForm-directive.html) directive!
什么`NgForm`指令?我们没有添加过[NgForm](../api/common/index/NgForm-directive.html)指令啊!

View File

@ -1 +1 @@
!= partial("../glossary")
include ../glossary

View File

@ -52,7 +52,7 @@ block includes
:marked
Inside the interpolation expression we flow the component's `birthday` value through the
[pipe operator](./template-syntax.html#pipe) ( | ) to the [Date pipe](../api/common/DatePipe-class.html)
[pipe operator](./template-syntax.html#pipe) ( | ) to the [Date pipe](../api/common/index/DatePipe-class.html)
function on the right. All pipes work this way.
在这个插值表达式中,我们让组件的`birthday`值通过[管道操作符](./template-syntax.html#pipe)( | )流动到
@ -140,7 +140,7 @@ figure.image-display
.l-sub-section
:marked
Learn more about the `DatePipes` format options in the [API Docs](../api/common/DatePipe-class.html).
Learn more about the `DatePipes` format options in the [API Docs](../api/common/index/DatePipe-class.html).
要了解更多`DatePipes`的格式选项,请参阅[API文档](../api/common/index/DatePipe-class.html)。
@ -624,7 +624,7 @@ figure.image-display
header Debugging with the json pipe
header 借助json管道进行调试
:marked
The [JsonPipe](../api/common/JsonPipe-class.html)
The [JsonPipe](../api/common/index/JsonPipe-class.html)
provides an easy way to diagnosis a mysteriously failing data binding or
inspect an object for future binding.

View File

@ -1465,7 +1465,7 @@ code-example(format=".", language="bash").
.l-sub-section
:marked
Learn about the [APP_BASE_HREF](../api/router/APP_BASE_HREF-let.html)
Learn about the [APP_BASE_HREF](../api/common/index/APP_BASE_HREF-let.html)
in the API Guide.
:marked
### *HashLocationStrategy*

View File

@ -231,11 +231,11 @@ include ../_util-fns
我们将把这份配置数组传给`provideRouter()`函数,它返回一个经过配置的*Router*[服务提供商](dependency-injection.html#!#injector-providers)(以及别的东西)。
Finally, we export this provider in the `APP_ROUTER_PROVIDERS` array
Finally, we export this provider in the `appRouterProviders` array
so we can simplify registration of router dependencies later in `main.ts`.
We don't have any other providers to register right now. But we will.
最后,我们通过`APP_ROUTER_PROVIDERS`数组导出这个提供商,以便我们以后将来在`main.ts`中简单的注册路由器依赖。
最后,我们通过`appRouterProviders`数组导出这个提供商,以便我们以后将来在`main.ts`中简单的注册路由器依赖。
目前我们还没有注册任何别的提供商,但很快就会这么做了!
:marked
@ -743,11 +743,11 @@ h4#define-routes 定义一些路由
我们的第一个配置中定义了由两个路由构成的数组,它们分别通过路径(path)导航到了`CrisisListComponent`和`HeroListComponent`组件。
Each definition translates to a [Route](../api/router/index/Route-class.html) object which has a
Each definition translates to a [Route](../api/router/index/Route-interface.html) object which has a
`path`, the URL path segment for this route, and a
`component`, the component associated with this route.
每个定义都被翻译成了一个[Route](../api/router/index/Route-class.html)对象。该对象有一个`path`字段表示该路由中的URL路径部分和一个`component`字段,表示与该路由相关联的组件。
每个定义都被翻译成了一个[Route](../api/router/index/Route-interface.html)对象。该对象有一个`path`字段表示该路由中的URL路径部分和一个`component`字段,表示与该路由相关联的组件。
The router draws upon its registry of such route definitions when the browser URL changes
or when our code tells the router to navigate along a route path.
@ -780,15 +780,15 @@ h4#provideRouter 调用<i>provideRouter</i>
我们把路由配置传给`provideRouter`函数,它返回一个数组,其中包括配置好的`Router`服务提供商……和路由库所需的某些你从未见过的提供商。
:marked
We add the `provideRouter` array to an `APP_ROUTER_PROVIDERS` array and export it.
We add the `provideRouter` array to an `appRouterProviders` array and export it.
我们把`provideRouter`数组加进一个`APP_ROUTER_PROVIDERS`数组,并导出它。
We could add *additional* service providers to `APP_ROUTER_PROVIDERS` &mdash;
We could add *additional* service providers to `appRouterProviders` &mdash;
providers that are specific to our routing configuration.
We don't have any yet. We will have some later in this chapter.
我们还可以往`APP_ROUTER_PROVIDERS`中添加一些*额外的*提供商,这取决于路由的具体配置。
我们还可以往`appRouterProviders`中添加一些*额外的*提供商,这取决于路由的具体配置。
虽然目前还一个都没有呢,不过稍后就会看到了。
.l-sub-section
@ -809,10 +809,10 @@ h4#register-providers 在启动时注册路由
本应用的启动点位于`/app`目录下的`main.ts`文件中。
这个文件很短,并且和默认的`main.ts`没有什么不同。
The important difference: we import the `APP_ROUTER_PROVIDERS` array
The important difference: we import the `appRouterProviders` array
and pass it as the second parameter of the `bootstrap` function.
最重要的不同点是:这里我们导入了`APP_ROUTER_PROVIDERS`数组,并且把它作为第二个参数传给了`bootstrap`函数。
最重要的不同点是:这里我们导入了`appRouterProviders`数组,并且把它作为第二个参数传给了`bootstrap`函数。
+makeExample('router/ts/app/main.1.ts','all', 'main.ts')(format=".")
@ -1896,7 +1896,7 @@ code-example(format="").
当用户点击了“Crisis Center”链接或者在地址栏粘贴`localhost:3000/crisis-center/`时,我们更希望该应用能直接显示危机列表。这就是默认路由。
The preferred solution is to add a `redirect` route that transparently translates from the initial relative URL (`''`)
The preferred solution is to add a `redirect` route that transparently translates from the initial relative URL (`''`)
to the desired default path (`/crisis-center`):
首选的解决方案是添加一个`redirect`路由它会把初始的相对URL`''`)悄悄翻译成默认路径(`/crisis-center`)。
@ -1914,21 +1914,21 @@ code-example(format="").
.l-sub-section
:marked
Technically, `pathMatch = 'full'` results in a route hit when the *remaining*, unmatched segments of the URL match `''`.
Technically, `pathMatch = 'full'` results in a route hit when the *remaining*, unmatched segments of the URL match `''`.
In our example, the redirect is at the top level of the route configuration tree so the *remaining* URL and the *entire* URL
are the same thing.
The other possible `pathMatch` value is `'prefix'` which tells the router
The other possible `pathMatch` value is `'prefix'` which tells the router
to match the redirect route when the *remaining* URL ***begins*** with the redirect route's _prefix_ path.
That's not what we want to do here. If the `pathMatch` value were `'prefix'`,
_every_ URL would match `''`.
We could never navigate to `/crisis-center/1` because the redirect route would match first and
That's not what we want to do here. If the `pathMatch` value were `'prefix'`,
_every_ URL would match `''`.
We could never navigate to `/crisis-center/1` because the redirect route would match first and
send us to the `CrisisListComponent`.
We should redirect to the `CrisisListComponent` _only_ when the _entire (remaining)_ url is `''`.
Learn more in Victor Savkin's blog
Learn more in Victor Savkin's blog
[post on redirects](http://victorsavkin.com/post/146722301646/angular-router-empty-paths-componentless-routes).
We'll discuss redirects in more detail in a future update to this chapter.
@ -2357,10 +2357,10 @@ h3#can-deactivate-guard <i>CanDeactivate</i>:处理未保存的更改
+makeExample('router/ts/app/crisis-center/crisis-center.routes.4.ts', '', 'crisis-center.routes.ts')
:marked
We also need to add the `Guard` to our main `APP_ROUTER_PROVIDERS` so the `Router` can inject it during the navigation process.
我们还要把这个`Guard`添加到主文件的`APP_ROUTER_PROVIDERS`中去,以便`Router`可以在导航过程中注入它。
We also need to add the `Guard` to our main `appRouterProviders` so the `Router` can inject it during the navigation process.
我们还要把这个`Guard`添加到主文件的`appRouterProviders`中去,以便`Router`可以在导航过程中注入它。
+makeExample('router/ts/app/app.routes.ts', '', 'app.routes.ts')
:marked

View File

@ -684,7 +684,7 @@ code-example(format="." language="javascript").
+ifDocsFor('ts')
:marked
[Headers](../api/http/Headers-class.html) are one of the [RequestOptions](../api/http/RequestOptions-class.html).
[Headers](../api/http/index/Headers-class.html) are one of the [RequestOptions](../api/http/index/RequestOptions-class.html).
Compose the options object and pass it in as the *third* parameter of the `post` method, as shown above.
[Headers](../api/http/index/Headers-class.html)是[RequestOptions](../api/http/index/RequestOptions-class.html)中的一员。

View File

@ -108,10 +108,6 @@ a(id='toc')
1. [生命周期钩子](#lifecycle-hooks)
1. [Routing](#routing)
1. [路由](#routing)
1. [Appendix](#appendix)
1. [附录](#appendix)
@ -121,11 +117,10 @@ a(id='toc')
## Single Responsibility
## 单一职责
We apply the [Single Responsibility Principle](https:\/\/en.wikipedia.org/wiki/Single_responsibility_principle) to all Components, Services, and other symbols we create.
This helps make our app cleaner, easier to read and maintain, and more testable.
We apply the [Single Responsibility Principle](https://wikipedia.org/wiki/Single_responsibility_principle) to all Components, Services, and other symbols we create. This helps make our app cleaner, easier to read and maintain, and more testable.
我们遵循[单一职责原则](https:\/\/en.wikipedia.org/wiki/Single_responsibility_principle)来创建的所有组件、服务和其它标志等。这样能帮助我们把应用程序弄的干净整洁,易于阅读、维护和测试。
### <a id="01-01"></a>Rule of One
### <a id="01-01"></a>单一法则
#### <a href="#01-01">Style 01-01</a>

View File

@ -33,7 +33,7 @@ include ../_util-fns
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
we introduced in the [QuickStart](../quickstart.html) and
the [Tour of Heroes](../tutorial/) tutorial
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
such as <code>npm</code>, <code>gulp</code>, and <code>lite-server</code>.
这一章单元测试是在其它章节的基础上写的。我们建议你按顺序阅读它们。同时我们假设你已经对Angular 2的原理、[“快速起步”](../quickstart.html)和
[英雄指南](../tutorial)中介绍的<code>npm</code>、<code>gulp</code>和<code>live-server</code>等工具都已经有所了解。
@ -72,25 +72,38 @@ include ../_util-fns
pre.prettyprint.lang-bash
code npm install jasmine-core --save-dev --save-exact
.alert.is-important
:marked
Be sure to install <code>jasmine-core</code> , not <code>jasmine</code>!
.alert.is-important Be sure to install <code>jasmine-core</code> , not <code>jasmine</code>!
.alert.is-important 请确保安装的是<code>jasmine-core</code>,而不是<code>jasmine</code>
.l-main-section
:marked
## Configure `lite-server` for serving our test harness
## 配置`lite-server`来提供测试环境
:marked
First create a configuration file for serving up our test harness through `lite-server`.
首先为提供测试环境的`lite-server`创建一个配置文件。
+makeExample('testing/ts/liteserver-test-config.json', '', 'liteserver-test-config.json')
请确保安装的是<code>jasmine-core</code>,而不是<code>jasmine</code>
:marked
Let's make one more change to the `package.json` script commands.
让我们在`package.json`的脚本命令区再做一项修改。
**Open the `package.json` ** and scroll to the `scripts` node and add in a new one:
**Open the `package.json` ** and scroll to the `scripts` node and add the following two entries:
**打开`package.json`**,滚动到`scripts`节点,添加下面这一行:
**打开`package.json`**,滚动到`scripts`节点,添加下面行:
code-example(format="").
"test": "live-server --open=unit-tests.html"
"lite-server-test": "lite-server --config=liteserver-test-config.json",
"test": "tsc && concurrently \"npm run tsc:w\" \"npm run lite-server-test\" "
:marked
That command will launch `live-server` and open a browser to the `unit-tests.html` page we just wrote.
The `npm test` command will launch `lite-server` and open a browser to the `unit-tests.html` page we just wrote. It will also take care of recompiling your source code and reloading your browser after any change.
该指令将启动`live-server`,并在浏览器中打开我们刚写的`unit-tests.html`页面。
@ -236,7 +249,7 @@ code-example(format="").
### Run and Fail
### 运行,并失败
Look over at the browser (live-server will have reloaded it). The browser displays
Look over at the browser (lite-server will have reloaded it). The browser displays
看看浏览器(live-server应该已经刷新了它)。其中显示的是:

View File

@ -191,7 +191,7 @@ pre.prettyprint.lang-bash
我们希望这些测试能快速进化,如果浏览器能在我们做出修改和重新编译时自动刷新就好了。
Lets launch with **live-server** in a second terminal window:
Lets launch with **lite-server** in a second terminal window:
没问题,让我们在另一个终端窗口中启动**live-server**

View File

@ -91,7 +91,7 @@ include ../_util-fns
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
we introduced in the [QuickStart](../quickstart.html) and
the [Tour of Heroes](../tutorial/) tutorial
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
such as <code>npm</code>, <code>gulp</code>, and <code>lite-server</code>.
这一章单元测试是在其它章节的基础上写的。我们建议你按顺序阅读它们。同时我们假设你已经对Angular 2的原理、[“快速起步”](../quickstart.html)和
[英雄指南](../tutorial)中介绍的<code>npm</code>、<code>gulp</code>和<code>live-server</code>等工具都已经有所了解。

View File

@ -360,11 +360,11 @@ code-example(language="bash").
### 让路由器生效
The *Component Router* is a service. We have to import our `APP_ROUTER_PROVIDERS` which
The *Component Router* is a service. We have to import our `appRouterProviders` which
contains our configured router and make it available to the application by adding it to
the `bootstrap` array.
*组件路由器*是一个服务。我们得导入`APP_ROUTER_PROVIDERS`(它包含了我们配置好的路由器),并通过把它添加到`bootstrap`的数组参数中让它在此应用中可用。
*组件路由器*是一个服务。我们得导入`appRouterProviders`(它包含了我们配置好的路由器),并通过把它添加到`bootstrap`的数组参数中让它在此应用中可用。
+makeExample('toh-5/ts/app/main.ts', '', 'app/main.ts')(format=".")

View File

@ -4,6 +4,19 @@
.clear
.grid-fluid
.c6
.article-card
.date July 11, 2016
.title
a(
target="_blank"
href="http://angularjs.blogspot.com/2016/07/angular-in-china-and-beyond-introducing.html"
) Angular in China and beyond: Introducing angular.cn
p We're excited to share the newly-launched angular.cn with you! Read on to learn how we did it, and how you can get involved in bringing Angular to your locale....
.author
img(src="/resources/images/bios/naomi.jpg")
.posted Posted by <b>Naomi Black</b>
.c6
.article-card
.date June 30, 2016
@ -17,20 +30,6 @@
img(src="/resources/images/bios/stephenfluin.jpg")
.posted Posted by <b>Stephen Fluin</b>
.c6
.article-card
.date June 21, 2016
.title
a(
target="_blank"
href="http://angularjs.blogspot.com/2016/06/rc3-now-available.html"
) RC3 Now Available
p Today were happy to announce that we are shipping Angular 2.0.0-rc3. This release includes a fix for a major performance regression in RC2...
.author
img(src="/resources/images/bios/stephenfluin.jpg")
.posted Posted by <b>Stephen Fluin</b>
.grid-fluid.l-space-bottom-2.l-space-top-4
.c12.text-center
h3.text-headline.text-uppercase Developer Community
@ -44,7 +43,7 @@
target="_blank"
href="http://www.bennadel.com/blog/3116-using-an-item-template-with-an-html-dropdown-menu-component-in-angular-2-rc-3.htm"
) Using An Item Template With An HTML Dropdown Menu Component
p A while ago, I played around with trying to create an HTML Dropdown menu component in Angular 2. I discovered that you could pass Template references into components for dynamic rendering....
p A while ago, I played around with trying to create an HTML Dropdown menu component in Angular 2. I discovered that you could pass Template references into components for dynamic rendering...
.author
img(src="/resources/images/bios/shield-bio-placeholder.png")
.posted Posted by <b>Ben Nadel</b>
@ -70,23 +69,23 @@
target="_blank"
href="http://blog.mgechev.com/2016/06/26/tree-shaking-angular2-production-build-rollup-javascript/"
) Building an Angular 2 Application for Production
p During the keynote of ng-conf, the core team managed to drop the size of the “Hello world!” app to less than 50K! In this blog post well explain all the steps we need to go through in order to achieve such results!.
p During the keynote of ng-conf, the core team managed to drop the size of the “Hello world!” app to less than 50K! In this blog post well explain all the steps we need to go through in order to achieve such results!
.author
img(src="/resources/images/bios/shield-bio-placeholder.png")
.posted Posted by <b>Minko Gechev</b>
.c6
.article-card
.date June 14, 2016
.date June 22, 2016
.title
a(
target="_blank"
href="http://blog.thoughtram.io/angular/2016/06/14/routing-in-angular-2-revisited.html"
) Routing in Angular 2 Revisited
p Just recently, the Angular team announced yet another version of the new router. Take a first look at the new and better APIs, touching on the most common scenarios...
href="https://mp.weixin.qq.com/s?__biz=MzIwNjQwMzUwMQ==&mid=2247483837&idx=1&sn=932b359504eec2ae50a3bcba2964b3c2&scene=2&srcid=0622Tab8nj3W3cAkphohB8wM"
) Why I chose Angular 2 / 我为什么选择Angular 2 (in Chinese)
p Ralph Wang, a senior developer with 18 years experience in China, tells why he chooses Angular 2. No choice is painful, but too many choices can be chaotic and cause even more pain...
.author
img(src="/resources/images/bios/pascalprecht.jpg")
.posted Posted by <b>Pascal Precht</b>
img(src="/resources/images/bios/angular-gde-bio-placeholder.png")
.posted Posted by <b>Ralph Wang</b>
.grid-fluid.l-space-bottom-2.l-space-top-4

View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -ex -o pipefail
./scripts/deploy-install.sh
(cd ../angular && git checkout master)

5
scripts/deploy-install.sh Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -ex -o pipefail
(cd ../ && git clone https://github.com/angular/angular.git --branch $LATEST_RELEASE)

View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -ex -o pipefail
./scripts/examples-install.sh
(cd public/docs/_examples && npm install angular/{core,common,compiler,platform-browser,platform-browser-dynamic,http,forms,router-deprecated,router,upgrade}-builds --no-optional)

View File

@ -2,7 +2,6 @@
set -ex -o pipefail
npm install --no-optional
(cd public/docs/_examples && npm install --no-optional)
(cd public/docs/_examples/_protractor && npm install --no-optional)
npm run webdriver:update --prefix public/docs/_examples/_protractor

View File

@ -0,0 +1,4 @@
// A ts2dart compiler annotation that can be ignored in API docs.
module.exports = function() {
return { name: 'Annotation', ignore: true };
};

View File

@ -1,9 +1,11 @@
module.exports = [
require('./Annotation'),
require('./deprecated'),
require('./howToUse'),
require('./whatItDoes'),
require('./internal'),
require('./stable'),
require('./ts2dart_const'),
require('./experimental'),
require('./docsNotRequired'),
require('./security'),

View File

@ -0,0 +1,4 @@
// A ts2dart compiler annotation that can be ignored in API docs.
module.exports = function() {
return { name: 'ts2dart_const', ignore: true };
};

View File

@ -23,8 +23,7 @@ module.exports = function addNotYetDocumentedProperty(EXPORT_DOC_TYPES, log, cre
}
if (doc.notYetDocumented) {
// TODO: (ericjim) should I remove this?
log.warn(createDocMessage("Not yet documented", doc));
log.info(createDocMessage("Not yet documented", doc));
}
});
@ -35,4 +34,4 @@ module.exports = function addNotYetDocumentedProperty(EXPORT_DOC_TYPES, log, cre
function notYetDocumented(doc) {
return !doc.noDescription && doc.description.trim().length == 0;
}
}

View File

@ -3,18 +3,25 @@ var Package = require('dgeni').Package;
module.exports = new Package('links', [])
.factory(require('./inline-tag-defs/link'))
.factory(require('./inline-tag-defs/linkDevGuide'))
.factory(require('./inline-tag-defs/linkDocs'))
.factory(require('./inline-tag-defs/example'))
.factory(require('./inline-tag-defs/exampleTabs'))
.factory(require('dgeni-packages/links/services/getAliases'))
.factory(require('dgeni-packages/links/services/getDocFromAlias'))
.factory(require('./services/getLinkInfo'))
.factory(require('./services/parseArgString'))
.factory(require('./services/moduleScopeLinkDisambiguator'))
.factory(require('./services/deprecatedDocsLinkDisambiguator'))
.factory(require('./services/getApiFragmentFileName'))
.config(function(inlineTagProcessor, linkInlineTagDef, linkDevGuideInlineTagDef, exampleInlineTagDef, exampleTabsInlineTagDef) {
.config(function(inlineTagProcessor, linkInlineTagDef, linkDocsInlineTagDef, exampleInlineTagDef, exampleTabsInlineTagDef) {
inlineTagProcessor.inlineTagDefinitions.push(linkInlineTagDef);
inlineTagProcessor.inlineTagDefinitions.push(linkDevGuideInlineTagDef);
inlineTagProcessor.inlineTagDefinitions.push(linkDocsInlineTagDef);
inlineTagProcessor.inlineTagDefinitions.push(exampleInlineTagDef);
inlineTagProcessor.inlineTagDefinitions.push(exampleTabsInlineTagDef);
})
.config(function(getLinkInfo, moduleScopeLinkDisambiguator, deprecatedDocsLinkDisambiguator) {
getLinkInfo.disambiguators.push(moduleScopeLinkDisambiguator);
getLinkInfo.disambiguators.push(deprecatedDocsLinkDisambiguator);
});

Some files were not shown because too many files have changed in this diff Show More