diff --git a/.gitignore b/.gitignore index 2666d27c27..df612cd56e 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ public/docs/xref-*.* _zip-output www* npm-debug*.log* +**/debug.log *.plnkr.html plnkr.html *.eplnkr.html diff --git a/.travis.yml b/.travis.yml index 394e81297a..2e3b260e29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ env: - DBUS_SESSION_BUS_ADDRESS=/dev/null - DISPLAY=:99.0 - CHROME_BIN=chromium-browser - - LATEST_RELEASE=2.1.1 + - LATEST_RELEASE=2.2.0 - TASK_FLAGS="--dgeni-log=warn" matrix: - TASK=lint diff --git a/gulpfile.js b/gulpfile.js index 5412201fdb..5a69023cfd 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -247,15 +247,16 @@ function findAndRunE2eTests(filter, outputFile) { e2eSpecPaths.forEach(function(specPath) { // get all of the examples under each dir where a pcFilename is found localExamplePaths = getExamplePaths(specPath, true); - // Filter by language - localExamplePaths = localExamplePaths.filter(function (fn) { - return fn.match('/'+lang+'$') != null; - }); + // Filter by example name if (filter) { localExamplePaths = localExamplePaths.filter(function (fn) { return fn.match(filter) != null; }) } + // Filter by language, also supports variations like js-es6 + localExamplePaths = localExamplePaths.filter(function (fn) { + return fn.match('/'+lang+'(?:-[^/]*)?$') != null; + }); localExamplePaths.forEach(function(examplePath) { examplePaths.push(examplePath); }) @@ -754,7 +755,7 @@ gulp.task('check-deploy', ['firebase-use-proj-check', 'build-docs'], () => { }).then(function(shouldDeploy) { if (shouldDeploy) { gutil.log('deploying...'); - return execPromise(`firebase deploy -p ${WWW}`); + return execPromise('firebase deploy'); } else { return ['Not deploying']; } @@ -792,7 +793,9 @@ gulp.task('link-checker', function(done) { '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/*' + '*/angular/tree/*', + // harp.json "bios" for "Ryan Schmukler", URL isn't valid: + 'http://slingingcode.com' ]; var blcOptions = { requestMethod: method, excludedKeywords: exclude}; return linkChecker({ blcOptions: blcOptions }); @@ -1274,7 +1277,7 @@ function apiExamplesWatch(postShredAction) { } function devGuideExamplesWatch(shredOptions, postShredAction, focus) { - var watchPattern = focus ? '**/{' + focus + ',cb-' + focus+ '}/**/*.*' : '**/*.*'; + var watchPattern = focus ? '{' + focus + ',cb-' + focus+ '}/**/*.*' : '**/*.*'; var includePattern = path.join(shredOptions.examplesDir, watchPattern); // removed this version because gulp.watch has the same glob issue that dgeni has. // var excludePattern = '!' + path.join(shredOptions.examplesDir, '**/node_modules/**/*.*'); diff --git a/harp.json b/harp.json index 648e23e405..efdf6a8905 100644 --- a/harp.json +++ b/harp.json @@ -31,7 +31,7 @@ "picture": "/resources/images/bios/naomi.jpg", "twitter": "naomitraveller", "website": "http://google.com/+NaomiBlack", - "bio": "Naomi is Angular's TPM generalist and jack-of-all-trades. She leads Angular Material and AngularDart, and acts as webmaster for angular.io. She's been at Google since 2006, as a technical program manager on projects ranging from Accessibility to Google Transit. She fights daleks in her spare time.", + "bio": "Naomi is Angular's TPM generalist and jack-of-all-trades. She leads Angular's global programs (including localization), supports Angular's internal Google users, and acts as webmaster for angular.io and angular.cn. She's been at Google since 2006, as a technical program manager on projects ranging from Accessibility to Google Transit. She fights daleks in her spare time.", "type": "Lead" }, @@ -40,7 +40,7 @@ "picture": "/resources/images/bios/brad-green.jpg", "twitter": "bradlygreen", "website": "https://plus.google.com/+BradGreen", - "bio": "Brad Green works at Google as an engineering director. Brad manages the Google Sales Platform suite of projects as well as the AngularJS framework. Prior to Google, Brad worked on the early mobile web at AvantGo, founded and sold startups, and spent a few hard years toiling as a caterer. Brad's first job out of school was as lackey to Steve Jobs at NeXT Computer writing demo software and designing his slide presentations. Brad lives in Mountain View, CA with his wife and two children.", + "bio": "Brad Green works at Google as an engineering director. Brad manages the Google Sales Platform suite of projects as well as the AngularJS framework. Prior to Google, Brad worked on the early mobile web at AvantGo, founded and sold startups, and spent a few hard years toiling as a caterer. Brad's first job out of school was as lackey to Steve Jobs at NeXT Computer writing demo software and designing his slide presentations. Brad enjoys throwing dinner parties with his wife Heather and putting on plays with his children.", "type": "Lead" }, @@ -49,7 +49,7 @@ "picture": "/resources/images/bios/juleskremer.jpg", "twitter": "jules_kremer", "website": "https://plus.google.com/+JulesKremer", - "bio": "Jules is a TPM on the Angular team. When not working with developers, Jules is often bending into pretzel-like shapes, climbing mountains or drinking really awesome beer.", + "bio": "Jules is Head of Angular Developer Relations at Google. When not working with developers, Jules is often bending into pretzel-like shapes, climbing mountains or drinking really awesome beer.", "type": "Lead" }, diff --git a/public/_includes/_footer.jade b/public/_includes/_footer.jade index 21113616e9..db6f393081 100644 --- a/public/_includes/_footer.jade +++ b/public/_includes/_footer.jade @@ -22,7 +22,7 @@ div(class="main-footer" data-swiftype-index="false") //li Libraries li About li 关于 - li Books & Training + li Books & Training li 书籍与培训 li Tools & Libraries li 工具与库 @@ -68,7 +68,7 @@ div(class="main-footer" data-swiftype-index="false") h3.text-headline 其它语种 ul.text-body - li English + li 中文版 footer(class="background-midnight") small.text-caption Powered by Google ©2010-2016. Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0. @@ -77,6 +77,6 @@ div(class="main-footer" data-swiftype-index="false") a(aria-label="查看风格指南" href="/docs/ts/latest/styleguide.html" title="风格指南" class="styleguide-trigger text-snow translated-cn" md-button) span.icon-favorite - p + p small.text-caption 本网站由洛阳永欣维护   a(href="http://www.miitbeian.gov.cn/") 豫ICP备16019859号-1 diff --git a/public/_includes/_util-fns.jade b/public/_includes/_util-fns.jade index 29639891e5..513d9af590 100644 --- a/public/_includes/_util-fns.jade +++ b/public/_includes/_util-fns.jade @@ -38,12 +38,16 @@ //- Location of sample code - var _liveLink = 'live link'; +- var _ngRepoURL = 'https://github.com/angular/angular'; +- var _ngDocRepoURL = 'https://github.com/angular/angular.io'; +- var _qsRepo = 'https://github.com/angular/quickstart/blob/master/README.md' //- NgModule related - var _AppModuleVsAppComp = 'AppModule' - var _appModuleTsVsAppCompTs = 'app/app.module.ts' - var _appModuleTsVsMainTs = 'app/app.module.ts' - var _bootstrapModule = 'bootstrapModule' +- var _declsVsDirectives = 'declarations' - var _moduleVsComp = 'module' - var _moduleVsRootComp = 'module' - var _platformBrowserDynamicVsBootStrap = 'platformBrowserDynamic' diff --git a/public/_includes/_version-dropdown.jade b/public/_includes/_version-dropdown.jade index d54f759625..e3a63188e1 100644 --- a/public/_includes/_version-dropdown.jade +++ b/public/_includes/_version-dropdown.jade @@ -61,16 +61,16 @@ if language == 'dart' else - var title = 'Angular ' + version + ' for Dart' +if current.path[4] !== 'change-log' + //- DROPDOWN BUTTON + nav.dropdown + button(aria-label="选择Angular版本" md-button class="dropdown-button" ng-click="appCtrl.toggleVersionMenu($event)") #{title} + div(class="overlay ng-hide" ng-click="appCtrl.toggleVersionMenu($event)" ng-show="appCtrl.showMenu") - -nav.dropdown - button(aria-label="选择Angular版本" md-button class="dropdown-button" ng-click="appCtrl.toggleVersionMenu($event)") #{title} - div(class="overlay ng-hide" ng-click="appCtrl.toggleVersionMenu($event)" ng-show="appCtrl.showMenu") - - - ul(class="dropdown-menu" ng-class="appCtrl.showMenu ? 'is-visible' : ''") - mixin tree(public.docs.ts, "/docs/ts", "Angular for TypeScript") - mixin tree(public.docs.js, "/docs/js", "Angular for JavaScript") - //- Disable cross-language link for API entry pages (but keep for top API search page): - if ! (current.path[3] === 'api' && public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]]) - mixin tree(public.docs.dart, "/docs/dart", "Angular for Dart") + //- DROPDOWN MENU + ul(class="dropdown-menu" ng-class="appCtrl.showMenu ? 'is-visible' : ''") + mixin tree(public.docs.ts, "/docs/ts", "Angular for TypeScript") + mixin tree(public.docs.js, "/docs/js", "Angular for JavaScript") + //- Disable cross-language link for API entry pages (but keep for top API search page): + if ! (current.path[3] === 'api' && public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]]) + mixin tree(public.docs.dart, "/docs/dart", "Angular for Dart") diff --git a/public/docs/_examples/.gitignore b/public/docs/_examples/.gitignore index b6733dc6ea..3d007625ef 100644 --- a/public/docs/_examples/.gitignore +++ b/public/docs/_examples/.gitignore @@ -11,10 +11,12 @@ wallaby.js _test-output **/ts/**/*.js +**/js-es6*/**/*.js **/ts-snippets/**/*.js *.d.ts !**/*e2e-spec.js !systemjs.config.1.js +!**/systemjs.config.extras.js !_boilerplate/* _boilerplate/a2docs.css diff --git a/public/docs/_examples/_boilerplate/package.json b/public/docs/_examples/_boilerplate/package.json index 3f255fcbd6..bcccdd978a 100644 --- a/public/docs/_examples/_boilerplate/package.json +++ b/public/docs/_examples/_boilerplate/package.json @@ -18,6 +18,7 @@ "build:webpack": "rimraf dist && webpack --config config/webpack.prod.js --bail", "build:cli": "ng build", "build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js", + "build:babel": "babel app -d app --extensions \".es6\" --source-maps", "copy-dist-files": "node ./copy-dist-files.js", "i18n": "ng-xi18n" }, diff --git a/public/docs/_examples/_boilerplate/plunker.README.md b/public/docs/_examples/_boilerplate/plunker.README.md deleted file mode 100644 index fa2e46f47a..0000000000 --- a/public/docs/_examples/_boilerplate/plunker.README.md +++ /dev/null @@ -1,2 +0,0 @@ -### Angular Documentation Example - diff --git a/public/docs/_examples/_boilerplate/systemjs.config.js b/public/docs/_examples/_boilerplate/systemjs.config.js index 457f040fc0..0d748b9e5e 100644 --- a/public/docs/_examples/_boilerplate/systemjs.config.js +++ b/public/docs/_examples/_boilerplate/systemjs.config.js @@ -21,8 +21,10 @@ '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'npm:@angular/http/bundles/http.umd.js', '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', // other libraries 'rxjs': 'npm:rxjs', diff --git a/public/docs/_examples/_boilerplate/systemjs.config.web.build.js b/public/docs/_examples/_boilerplate/systemjs.config.web.build.js index 3fa201a280..b340fc6159 100644 --- a/public/docs/_examples/_boilerplate/systemjs.config.web.build.js +++ b/public/docs/_examples/_boilerplate/systemjs.config.web.build.js @@ -11,19 +11,15 @@ // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER transpiler: 'ts', typescriptOptions: { - // Complete copy of compiler options in standard tsconfig.json + // Copy of compiler options in standard tsconfig.json "target": "es5", "module": "commonjs", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "removeComments": false, "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true, - "typeRoots": [ - "../../node_modules/@types/" - ] + "suppressImplicitAnyIndexErrors": true }, meta: { 'typescript': { @@ -48,8 +44,10 @@ '@angular/platform-browser-dynamic': 'ng:platform-browser-dynamic-builds/master/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'ng:http-builds/master/bundles/http.umd.js', '@angular/router': 'ng:router-builds/master/bundles/router.umd.js', + '@angular/router/upgrade': 'ng:router-builds/master/bundles/router-upgrade.umd.js', '@angular/forms': 'ng:forms-builds/master/bundles/forms.umd.js', '@angular/upgrade': 'ng:upgrade-builds/master/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'ng:upgrade-builds/master/bundles/upgrade-static.umd.js', // angular testing umd bundles (overwrite the shim mappings) '@angular/core/testing': 'ng:core-builds/master/bundles/core-testing.umd.js', @@ -80,10 +78,13 @@ } }); - if (!global.noBootstrap) { bootstrap(); } + if (global.autoBootstrap) { bootstrap(); } - // Bootstrap the `AppModule`(skip the `app/main.ts` that normally does this) + // Bootstrap with a default `AppModule` + // ignore an `app/app.module.ts` and `app/main.ts`, even if present + // This function exists primarily (exclusively?) for the QuickStart function bootstrap() { + console.log('Auto-bootstrapping'); // Stub out `app/main.ts` so System.import('app') doesn't fail if called in the index.html System.set(System.normalizeSync('app/main.ts'), System.newModule({ })); @@ -91,7 +92,7 @@ // bootstrap and launch the app (equivalent to standard main.ts) Promise.all([ System.import('@angular/platform-browser-dynamic'), - System.import('app/app.module') + getAppModule() ]) .then(function (imports) { var platform = imports[0]; @@ -101,4 +102,38 @@ .catch(function(err){ console.error(err); }); } + // Make the default AppModule + // returns a promise for the AppModule + function getAppModule() { + console.log('Making a bare-bones, default AppModule'); + + return Promise.all([ + System.import('@angular/core'), + System.import('@angular/platform-browser'), + System.import('app/app.component') + ]) + .then(function (imports) { + + var core = imports[0]; + var browser = imports[1]; + var appComp = imports[2].AppComponent; + + var AppModule = function() {} + + AppModule.annotations = [ + new core.NgModule({ + imports: [ browser.BrowserModule ], + declarations: [ appComp ], + bootstrap: [ appComp ] + }) + ] + return {AppModule: AppModule}; + }) + } })(this); + +/* +Copyright 2016 Google Inc. All Rights Reserved. +Use of this source code is governed by an MIT-style license that +can be found in the LICENSE file at http://angular.io/license +*/ diff --git a/public/docs/_examples/_boilerplate/systemjs.config.web.js b/public/docs/_examples/_boilerplate/systemjs.config.web.js index 40e6a67fc6..768d357ed7 100644 --- a/public/docs/_examples/_boilerplate/systemjs.config.web.js +++ b/public/docs/_examples/_boilerplate/systemjs.config.web.js @@ -9,19 +9,15 @@ // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER transpiler: 'ts', typescriptOptions: { - // Complete copy of compiler options in standard tsconfig.json + // Copy of compiler options in standard tsconfig.json "target": "es5", "module": "commonjs", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "removeComments": false, "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true, - "typeRoots": [ - "../../node_modules/@types/" - ] + "suppressImplicitAnyIndexErrors": true }, meta: { 'typescript': { @@ -45,8 +41,10 @@ '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'npm:@angular/http/bundles/http.umd.js', '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', // other libraries 'rxjs': 'npm:rxjs', @@ -67,10 +65,13 @@ } }); - if (!global.noBootstrap) { bootstrap(); } + if (global.autoBootstrap) { bootstrap(); } - // Bootstrap the `AppModule`(skip the `app/main.ts` that normally does this) + // Bootstrap with a default `AppModule` + // ignore an `app/app.module.ts` and `app/main.ts`, even if present + // This function exists primarily (exclusively?) for the QuickStart function bootstrap() { + console.log('Auto-bootstrapping'); // Stub out `app/main.ts` so System.import('app') doesn't fail if called in the index.html System.set(System.normalizeSync('app/main.ts'), System.newModule({ })); @@ -78,7 +79,7 @@ // bootstrap and launch the app (equivalent to standard main.ts) Promise.all([ System.import('@angular/platform-browser-dynamic'), - System.import('app/app.module') + getAppModule() ]) .then(function (imports) { var platform = imports[0]; @@ -88,4 +89,38 @@ .catch(function(err){ console.error(err); }); } + // Make the default AppModule + // returns a promise for the AppModule + function getAppModule() { + console.log('Making a bare-bones, default AppModule'); + + return Promise.all([ + System.import('@angular/core'), + System.import('@angular/platform-browser'), + System.import('app/app.component') + ]) + .then(function (imports) { + + var core = imports[0]; + var browser = imports[1]; + var appComp = imports[2].AppComponent; + + var AppModule = function() {} + + AppModule.annotations = [ + new core.NgModule({ + imports: [ browser.BrowserModule ], + declarations: [ appComp ], + bootstrap: [ appComp ] + }) + ] + return {AppModule: AppModule}; + }) + } })(this); + +/* +Copyright 2016 Google Inc. All Rights Reserved. +Use of this source code is governed by an MIT-style license that +can be found in the LICENSE file at http://angular.io/license +*/ diff --git a/public/docs/_examples/animations/ts/index.html b/public/docs/_examples/animations/ts/index.html index 76a7b93356..8188d14709 100644 --- a/public/docs/_examples/animations/ts/index.html +++ b/public/docs/_examples/animations/ts/index.html @@ -9,7 +9,7 @@ - + diff --git a/public/docs/_examples/architecture/dart/lib/sales_tax_component.dart b/public/docs/_examples/architecture/dart/lib/sales_tax_component.dart index 7f5ed5036c..4a1977ba06 100644 --- a/public/docs/_examples/architecture/dart/lib/sales_tax_component.dart +++ b/public/docs/_examples/architecture/dart/lib/sales_tax_component.dart @@ -11,10 +11,7 @@ import 'tax_rate_service.dart';
The sales tax is - {{ getTax(amountBox.value) | currency:'USD':false:'1.2-2' }} - + {{ getTax(amountBox.value) | currency:'USD':true:'1.2-2' }}
''', providers: const [SalesTaxService, TaxRateService]) diff --git a/public/docs/_examples/architecture/dart/pubspec.yaml b/public/docs/_examples/architecture/dart/pubspec.yaml index 4b7f63f5f0..007ec9f4e8 100644 --- a/public/docs/_examples/architecture/dart/pubspec.yaml +++ b/public/docs/_examples/architecture/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/architecture/e2e-spec.ts b/public/docs/_examples/architecture/e2e-spec.ts index c1ee8cf00d..e967804483 100644 --- a/public/docs/_examples/architecture/e2e-spec.ts +++ b/public/docs/_examples/architecture/e2e-spec.ts @@ -71,9 +71,7 @@ function salesTaxTests() { it('shows sales tax', async function () { let page = getPageElts(); page.salesTaxAmountInput.sendKeys('10', protractor.Key.ENTER); - // 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); + expect(page.salesTaxDetail.getText()).toEqual('The sales tax is $1.00'); }); } diff --git a/public/docs/_examples/architecture/ts/index.html b/public/docs/_examples/architecture/ts/index.html index 090bd17c7b..d22ff7f6e4 100644 --- a/public/docs/_examples/architecture/ts/index.html +++ b/public/docs/_examples/architecture/ts/index.html @@ -6,7 +6,7 @@ - + diff --git a/public/docs/_examples/attribute-directives/dart/pubspec.yaml b/public/docs/_examples/attribute-directives/dart/pubspec.yaml index d432cac246..4120561645 100644 --- a/public/docs/_examples/attribute-directives/dart/pubspec.yaml +++ b/public/docs/_examples/attribute-directives/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/attribute-directives/ts/index.html b/public/docs/_examples/attribute-directives/ts/index.html index 197f1a8280..f3b37e823a 100644 --- a/public/docs/_examples/attribute-directives/ts/index.html +++ b/public/docs/_examples/attribute-directives/ts/index.html @@ -7,7 +7,7 @@ - + diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/index.html b/public/docs/_examples/cb-a1-a2-quick-reference/ts/index.html index ee2eb6fdec..75e16b476c 100644 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/index.html +++ b/public/docs/_examples/cb-a1-a2-quick-reference/ts/index.html @@ -9,7 +9,7 @@ - + diff --git a/public/docs/_examples/cb-component-communication/ts/index.html b/public/docs/_examples/cb-component-communication/ts/index.html index 4afa076c19..d4c62ed916 100644 --- a/public/docs/_examples/cb-component-communication/ts/index.html +++ b/public/docs/_examples/cb-component-communication/ts/index.html @@ -9,7 +9,7 @@ - + diff --git a/public/docs/_examples/cb-component-relative-paths/ts/index.html b/public/docs/_examples/cb-component-relative-paths/ts/index.html index cc0d972df2..3a5c532b82 100644 --- a/public/docs/_examples/cb-component-relative-paths/ts/index.html +++ b/public/docs/_examples/cb-component-relative-paths/ts/index.html @@ -13,7 +13,7 @@ - + diff --git a/public/docs/_examples/cb-dependency-injection/ts/index.html b/public/docs/_examples/cb-dependency-injection/ts/index.html index ba1d2761e1..c978778d09 100644 --- a/public/docs/_examples/cb-dependency-injection/ts/index.html +++ b/public/docs/_examples/cb-dependency-injection/ts/index.html @@ -10,7 +10,7 @@ - + diff --git a/public/docs/_examples/cb-dynamic-form/ts/index.html b/public/docs/_examples/cb-dynamic-form/ts/index.html index ec3e1cbbb2..23d56ae14f 100644 --- a/public/docs/_examples/cb-dynamic-form/ts/index.html +++ b/public/docs/_examples/cb-dynamic-form/ts/index.html @@ -10,7 +10,7 @@ - + diff --git a/public/docs/_examples/cb-form-validation/ts/index.html b/public/docs/_examples/cb-form-validation/ts/index.html index 8fc614fe0f..54ad9c69ab 100644 --- a/public/docs/_examples/cb-form-validation/ts/index.html +++ b/public/docs/_examples/cb-form-validation/ts/index.html @@ -9,7 +9,7 @@ - + diff --git a/public/docs/_examples/cb-set-document-title/ts/index.html b/public/docs/_examples/cb-set-document-title/ts/index.html index 8f1ad96812..0543070fbd 100644 --- a/public/docs/_examples/cb-set-document-title/ts/index.html +++ b/public/docs/_examples/cb-set-document-title/ts/index.html @@ -14,7 +14,7 @@ - + diff --git a/public/docs/_examples/cb-ts-to-js/e2e-spec.ts b/public/docs/_examples/cb-ts-to-js/e2e-spec.ts index 5862beeebf..bc67bac8f0 100644 --- a/public/docs/_examples/cb-ts-to-js/e2e-spec.ts +++ b/public/docs/_examples/cb-ts-to-js/e2e-spec.ts @@ -1,4 +1,4 @@ -'use strict'; // necessary for es6 output in node +'use strict'; // necessary for es6 output in node import { browser, element, by } from 'protractor'; @@ -9,7 +9,7 @@ describe('TypeScript to Javascript tests', function () { }); it('should display the basic component example', function () { - testTag('hero-view', 'Hero: Windstorm'); + testTag('hero-view', 'Hero Detail: Windstorm'); }); it('should display the component example with lifecycle methods', function () { @@ -36,7 +36,7 @@ describe('TypeScript to Javascript tests', function () { it('should support component with inputs and outputs', function () { let app = element(by.css('hero-io')); - let confirmComponent = app.element(by.css('my-confirm')); + let confirmComponent = app.element(by.css('app-confirm')); confirmComponent.element(by.buttonText('OK')).click(); expect(app.element(by.cssContainingText('span', 'OK clicked')).isPresent()).toBe(true); @@ -46,11 +46,11 @@ describe('TypeScript to Javascript tests', function () { }); it('should support host bindings and host listeners', function() { - let app = element(by.css('heroes-bindings')); + let app = element(by.css('hero-host')); let h1 = app.element(by.css('h1')); expect(app.getAttribute('class')).toBe('heading'); - expect(app.getAttribute('title')).toBe('Tooltip content'); + expect(app.getAttribute('title')).toContain('Tooltip'); h1.click(); expect(h1.getAttribute('class')).toBe('active'); @@ -61,12 +61,12 @@ describe('TypeScript to Javascript tests', function () { }); it('should support content and view queries', function() { - let app = element(by.css('heroes-queries')); - let windstorm = app.element(by.css('a-hero:first-child')); + let app = element(by.css('hero-queries')); + let windstorm = app.element(by.css('view-child:first-child')); - app.element(by.buttonText('Activate')).click(); + app.element(by.css('button')).click(); expect(windstorm.element(by.css('h2')).getAttribute('class')).toBe('active'); - expect(windstorm.element(by.css('active-label')).getText()).toBe('Active'); + expect(windstorm.element(by.css('content-child')).getText()).toBe('Active'); }); function testTag(selector: string, expectedText: string) { diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/.babelrc b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/.babelrc new file mode 100644 index 0000000000..3aaf507508 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/.babelrc @@ -0,0 +1,6 @@ +{ + "presets": [ + "es2015", + "angular2" + ] +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/app.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/app.component.es6 new file mode 100644 index 0000000000..e5f158dbed --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/app.component.es6 @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: 'my-app', + templateUrl: 'app.component.html', + styles: [ + // See hero-di-inject-additional.component + 'hero-host, hero-host-meta { border: 1px dashed black; display: block; padding: 4px;}', + '.heading {font-style: italic}' + ] +}) +export class AppComponent { + title = 'ES6 JavaScript with Decorators'; +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/app.component.html b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/app.component.html new file mode 100644 index 0000000000..7f1efd31a0 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/app.component.html @@ -0,0 +1,31 @@ + +

{{title}}

+Classes and Class Metadata
+Input and Output Decorators
+Dependency Injection
+Host Metadata
+View and Child Metadata
+ +
+

Classes and Class Metadata

+ + + +
+

Input and Output Metadata

+ + +
+

Dependency Injection

+ + + + +
+

Host Metadata

+ + + +
+

View and Child Metadata

+ diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/app.module.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/app.module.es6 new file mode 100644 index 0000000000..bea55777ef --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/app.module.es6 @@ -0,0 +1,55 @@ +import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { ConfirmComponent } from './confirm.component'; +// #docregion appimport +import { HeroComponent } from './hero.component'; +// #enddocregion appimport +import { HeroComponent as HeroDIComponent } from './hero-di.component'; +import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component'; +import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component'; +import { HeroHostComponent } from './hero-host.component'; +import { HeroHostMetaComponent } from './hero-host-meta.component'; +import { HeroIOComponent } from './hero-io.component'; +import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component'; +import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component'; +import { HeroTitleComponent } from './hero-title.component'; + +import { DataService } from './data.service'; + +@NgModule({ + imports: [ + BrowserModule + ], + declarations: [ + AppComponent, + ConfirmComponent, + HeroComponent, + HeroDIComponent, + HeroDIInjectComponent, + HeroDIInjectAdditionalComponent, + HeroHostComponent, HeroHostMetaComponent, + HeroIOComponent, + HeroLifecycleComponent, + HeroQueriesComponent, ViewChildComponent, ContentChildComponent, + HeroTitleComponent + ], + providers: [ + DataService, + { provide: 'heroName', useValue: 'Windstorm' } + ], + bootstrap: [ AppComponent ], + + // schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging +}) +export class AppModule { } + +/* tslint:disable no-unused-variable */ +// #docregion ng2import +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { + LocationStrategy, + HashLocationStrategy +} from '@angular/common'; +// #enddocregion ng2import diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/confirm.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/confirm.component.es6 new file mode 100644 index 0000000000..08a0ed6c60 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/confirm.component.es6 @@ -0,0 +1,22 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +// #docregion +@Component({ + moduleId: module.id, + selector: 'app-confirm', + templateUrl: 'confirm.component.html' +}) +export class ConfirmComponent { + @Input() okMsg = ''; + @Input('cancelMsg') notOkMsg = ''; + @Output() ok = new EventEmitter(); + @Output('cancel') notOk = new EventEmitter(); + + onOkClick() { + this.ok.emit(true); + } + onNotOkClick() { + this.notOk.emit(true); + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/confirm.component.html b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/confirm.component.html new file mode 100644 index 0000000000..917bd1696f --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/confirm.component.html @@ -0,0 +1,6 @@ + + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/data.service.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/data.service.es6 new file mode 100644 index 0000000000..cd7f9e1aae --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/data.service.es6 @@ -0,0 +1,10 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class DataService { + constructor() { } + + getHeroName() { + return 'Windstorm'; + } +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-di-inject-additional.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-di-inject-additional.component.es6 new file mode 100644 index 0000000000..ec460a9dbc --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-di-inject-additional.component.es6 @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-di-inject-additional', + template: `` +}) +export class HeroComponent { } diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-di-inject.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-di-inject.component.es6 new file mode 100644 index 0000000000..94b42f956a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-di-inject.component.es6 @@ -0,0 +1,13 @@ +import { Component, Inject } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-di-inject', + template: `

Hero: {{name}}

` +}) +export class HeroComponent { + constructor(@Inject('heroName') name) { + this.name = name; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-di.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-di.component.es6 new file mode 100644 index 0000000000..0cc78d277e --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-di.component.es6 @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { DataService } from './data.service'; + +// #docregion +@Component({ + selector: 'hero-di', + template: `

Hero: {{name}}

` +}) +export class HeroComponent { + name = ''; + constructor(dataService: DataService) { + this.name = dataService.getHeroName(); + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-host-meta.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-host-meta.component.es6 new file mode 100644 index 0000000000..25dbe1c21a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-host-meta.component.es6 @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-host-meta', + template: ` +

Hero Host in Metadata

+
Heading clicks: {{clicks}}
+ `, + host: { + // HostBindings to the element + '[title]': 'title', + '[class.heading]': 'headingClass', + + // HostListeners on the entire element + '(click)': 'clicked()', + '(mouseenter)': 'enter($event)', + '(mouseleave)': 'leave($event)' + }, + // Styles within (but excluding) the element + styles: ['.active {background-color: coral;}'] +}) +export class HeroHostMetaComponent { + title = 'Hero Host in Metadata Tooltip'; + headingClass = true; + + active = false; + clicks = 0; + + clicked() { + this.clicks += 1; + } + + enter(event: Event) { + this.active = true; + this.headingClass = false; + } + + leave(event: Event) { + this.active = false; + this.headingClass = true; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-host.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-host.component.es6 new file mode 100644 index 0000000000..e8d72233c8 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-host.component.es6 @@ -0,0 +1,39 @@ +import { Component, HostBinding, HostListener } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-host', + template: ` +

Hero Host in Decorators

+
Heading clicks: {{clicks}}
+ `, + // Styles within (but excluding) the element + styles: ['.active {background-color: yellow;}'] +}) +export class HeroHostComponent { + // HostBindings to the element + @HostBinding() title = 'Hero Host in Decorators Tooltip'; + @HostBinding('class.heading') headingClass = true; + + active = false; + clicks = 0; + + // HostListeners on the entire element + @HostListener('click') + clicked() { + this.clicks += 1; + } + + @HostListener('mouseenter', ['$event']) + enter(event: Event) { + this.active = true; + this.headingClass = false; + } + + @HostListener('mouseleave', ['$event']) + leave(event: Event) { + this.active = false; + this.headingClass = true; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-io.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-io.component.es6 new file mode 100644 index 0000000000..4b36411e78 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-io.component.es6 @@ -0,0 +1,26 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-io', + template: ` + + + OK clicked + Cancel clicked + ` +}) +export class HeroIOComponent { + okClicked = false; + cancelClicked = false; + + onOk() { + this.okClicked = true; + } + + onCancel() { + this.cancelClicked = true; + } +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-lifecycle.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-lifecycle.component.es6 new file mode 100644 index 0000000000..2539266597 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-lifecycle.component.es6 @@ -0,0 +1,14 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-lifecycle', + template: `

Hero: {{name}}

` +}) +export class HeroComponent { + name = ''; + ngOnInit() { + // todo: fetch from server async + setTimeout(() => this.name = 'Windstorm', 0); + } +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-queries.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-queries.component.es6 new file mode 100644 index 0000000000..fced43d4d7 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-queries.component.es6 @@ -0,0 +1,81 @@ +import { + Component, + ContentChild, + Input, + QueryList, + ViewChildren +} from '@angular/core'; + +@Component({ + selector: 'content-child', + template: ` + + Active + ` +}) +export class ContentChildComponent { + active = false; + + activate() { + this.active = true; + } +} + +//////////////////// + +// #docregion content +@Component({ + selector: 'view-child', + template: ` +

+ {{hero.name}} + +

`, + styles: ['.active {font-weight: bold; background-color: skyblue;}'] +}) +export class ViewChildComponent { + @Input() hero; + active = false; + + @ContentChild(ContentChildComponent) content; + + activate() { + this.active = !this.active; + this.content.activate(); + } +} +// #enddocregion content + +//////////////////// + +// #docregion view +@Component({ + selector: 'hero-queries', + template: ` + + + + + ` +}) +export class HeroQueriesComponent { + active = false; + heroData = [ + {id: 1, name: 'Windstorm'}, + {id: 2, name: 'LaughingGas'} + ]; + + @ViewChildren(ViewChildComponent) views; + + activate() { + this.active = !this.active; + this.views.forEach( + view => view.activate() + ); + } + + get buttonLabel() { + return this.active ? 'Deactivate' : 'Activate'; + } +} +// #enddocregion view diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-title.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-title.component.es6 new file mode 100644 index 0000000000..25460d34f7 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-title.component.es6 @@ -0,0 +1,26 @@ +import { Attribute, Component, Inject, Optional } from '@angular/core'; + +// #docregion +// #docregion templateUrl +@Component({ + moduleId: module.id, + selector: 'hero-title', + templateUrl: 'hero-title.component.html' +}) +// #enddocregion templateUrl +export class HeroTitleComponent { + msg = ''; + constructor( + @Inject('titlePrefix') @Optional() titlePrefix, + @Attribute('title') title + ) { + this.titlePrefix = titlePrefix; + this.title = title; + } + + ok() { + this.msg = 'OK!'; + } +} +// #enddocregion + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-title.component.html b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-title.component.html new file mode 100644 index 0000000000..0e93122d5c --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero-title.component.html @@ -0,0 +1,4 @@ + +

{{titlePrefix}} {{title}}

+ +

{{ msg }}

diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero.component.es6 new file mode 100644 index 0000000000..4ea4c11611 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/hero.component.es6 @@ -0,0 +1,14 @@ +// #docregion metadata +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-view', + template: '

{{title}}: {{getName()}}

' +}) +// #docregion appexport, class +export class HeroComponent { + title = 'Hero Detail'; + getName() {return 'Windstorm'; } +} +// #enddocregion appexport, class +// #enddocregion metadata diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/main.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/main.es6 new file mode 100644 index 0000000000..2470c9595e --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/app/main.es6 @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/example-config.json b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/example-config.json new file mode 100644 index 0000000000..391bd1a766 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/example-config.json @@ -0,0 +1,4 @@ +{ + "build": "build:babel", + "run": "http-server:e2e" +} \ No newline at end of file diff --git a/public/docs/_examples/architecture/ts/mini-app.html b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/index.html similarity index 82% rename from public/docs/_examples/architecture/ts/mini-app.html rename to public/docs/_examples/cb-ts-to-js/js-es6-decorators/index.html index ecb7dd21ae..1b9e3b5211 100644 --- a/public/docs/_examples/architecture/ts/mini-app.html +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/index.html @@ -1,10 +1,11 @@ - Architecture of Angular + + TypeScript to JavaScript @@ -15,7 +16,7 @@ diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/plnkr.json b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/plnkr.json new file mode 100644 index 0000000000..5c7a5acd44 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/plnkr.json @@ -0,0 +1,8 @@ +{ + "description": "TypeScript to JavaScript", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ], + "tags":["cookbook"] +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/.babelrc b/public/docs/_examples/cb-ts-to-js/js-es6/.babelrc new file mode 100644 index 0000000000..3c078e9f99 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "es2015" + ] +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/app.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/app.component.es6 new file mode 100644 index 0000000000..9615b98a1f --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/app.component.es6 @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; + +export class AppComponent { + constructor() { + this.title = 'Plain ES6 JavaScript'; + } +} + +AppComponent.annotations = [ + new Component({ + moduleId: module.id, + selector: 'my-app', + templateUrl: 'app.component.html', + styles: [ + // See hero-di-inject-additional.component + 'hero-host { border: 1px dashed black; display: block; padding: 4px;}', + '.heading {font-style: italic}' + ] + }) +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/app.component.html b/public/docs/_examples/cb-ts-to-js/js-es6/app/app.component.html new file mode 100644 index 0000000000..8fbe65ade6 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/app.component.html @@ -0,0 +1,30 @@ + +

{{title}}

+Classes and Class Metadata
+Input and Output Metadata
+Dependency Injection
+Host Metadata
+View and Child Metadata
+ +
+

Classes and Class Metadata

+ + + +
+

Input and Output Metadata

+ + +
+

Dependency Injection

+ + + + +
+

Host Metadata

+ + +
+

View and Child Metadata

+ diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/app.module.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/app.module.es6 new file mode 100644 index 0000000000..e8c7a8f9c8 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/app.module.es6 @@ -0,0 +1,56 @@ +import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { ConfirmComponent } from './confirm.component'; +// #docregion appimport +import { HeroComponent } from './hero.component'; + +// #enddocregion appimport +import { HeroComponent as HeroDIComponent } from './hero-di.component'; +import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component'; +import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component'; +import { HeroHostComponent } from './hero-host.component'; +import { HeroIOComponent } from './hero-io.component'; +import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component'; +import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component'; +import { HeroTitleComponent } from './hero-title.component'; + +import { DataService } from './data.service'; + +export class AppModule { } + +AppModule.annotations = [ + new NgModule({ + imports: [ BrowserModule], + declarations: [ + AppComponent, + ConfirmComponent, + HeroComponent, + HeroDIComponent, + HeroDIInjectComponent, + HeroDIInjectAdditionalComponent, + HeroHostComponent, + HeroIOComponent, + HeroLifecycleComponent, + HeroQueriesComponent, ViewChildComponent, ContentChildComponent, + HeroTitleComponent + ], + providers: [ + DataService, + { provide: 'heroName', useValue: 'Windstorm' } + ], + bootstrap: [ AppComponent ], + + // schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging + }) +] + +/* tslint:disable no-unused-variable */ +// #docregion ng2import +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { + LocationStrategy, + HashLocationStrategy +} from '@angular/common'; +// #enddocregion ng2import diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/confirm.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/confirm.component.es6 new file mode 100644 index 0000000000..d42a553688 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/confirm.component.es6 @@ -0,0 +1,32 @@ +import { Component, EventEmitter } from '@angular/core'; + +// #docregion +export class ConfirmComponent { + constructor(){ + this.ok = new EventEmitter(); + this.notOk = new EventEmitter(); + } + onOkClick() { + this.ok.emit(true); + } + onNotOkClick() { + this.notOk.emit(true); + } +} + +ConfirmComponent.annotations = [ + new Component({ + moduleId: module.id, + selector: 'app-confirm', + templateUrl: 'confirm.component.html', + inputs: [ + 'okMsg', + 'notOkMsg: cancelMsg' + ], + outputs: [ + 'ok', + 'notOk: cancel' + ] + }) +]; +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/confirm.component.html b/public/docs/_examples/cb-ts-to-js/js-es6/app/confirm.component.html new file mode 100644 index 0000000000..917bd1696f --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/confirm.component.html @@ -0,0 +1,6 @@ + + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/data.service.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/data.service.es6 new file mode 100644 index 0000000000..de023ce5a0 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/data.service.es6 @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; + +export class DataService { + constructor() { + } + getHeroName() { + return 'Windstorm'; + } +} + +DataService.annotations = [ + new Injectable() +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-di-inject-additional.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-di-inject-additional.component.es6 new file mode 100644 index 0000000000..5eb9bab815 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-di-inject-additional.component.es6 @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +export class HeroComponent { } + +HeroComponent.annotations = [ + new Component({ + selector: 'hero-di-inject-additional', + template: `` + }) +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-di-inject.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-di-inject.component.es6 new file mode 100644 index 0000000000..2f95a0b981 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-di-inject.component.es6 @@ -0,0 +1,20 @@ +import { Component, Inject } from '@angular/core'; + +// #docregion +export class HeroComponent { + constructor(name) { + this.name = name; + } +} + +HeroComponent.annotations = [ + new Component({ + selector: 'hero-di-inject', + template: `

Hero: {{name}}

` + }) +]; + +HeroComponent.parameters = [ + [new Inject('heroName')] +]; +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-di.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-di.component.es6 new file mode 100644 index 0000000000..dfbecf0707 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-di.component.es6 @@ -0,0 +1,22 @@ +import { Component } from '@angular/core'; +import { DataService } from './data.service'; + +// #docregion +export class HeroComponent { + constructor(dataService) { + this.name = dataService.getHeroName(); + } +} + +HeroComponent.annotations = [ + new Component({ + selector: 'hero-di', + template: `

Hero: {{name}}

` + }) +]; + +HeroComponent.parameters = [ + [DataService] +]; + +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-host.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-host.component.es6 new file mode 100644 index 0000000000..092cd1a1ce --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-host.component.es6 @@ -0,0 +1,50 @@ +import { Component } from '@angular/core'; + +// #docregion +export class HeroHostComponent { + constructor() { + this.active = false; + this.clicks = 0; + this.headingClass = true; + this.title = 'Hero Host Tooltip'; + } + + clicked() { + this.clicks += 1; + } + + enter(event) { + this.active = true; + this.headingClass = false; + } + + leave(event) { + this.active = false; + this.headingClass = true; + } +} + +// #docregion metadata +HeroHostComponent.annotations = [ + new Component({ + selector: 'hero-host', + template: ` +

Hero Host

+
Heading clicks: {{clicks}}
+ `, + host: { + // HostBindings to the element + '[title]': 'title', + '[class.heading]': 'headingClass', + '(click)': 'clicked()', + + // HostListeners on the entire element + '(mouseenter)': 'enter($event)', + '(mouseleave)': 'leave($event)' + }, + // Styles within (but excluding) the element + styles: ['.active {background-color: yellow;}'] + }) +]; +// #docregion metadata +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-io.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-io.component.es6 new file mode 100644 index 0000000000..0dc8c08f2d --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-io.component.es6 @@ -0,0 +1,31 @@ +import { Component } from '@angular/core'; + +export class HeroIOComponent { + constructor() { + this.okClicked = false; + this.cancelClicked = false; + } + + onOk() { + this.okClicked = true; + } + + onCancel() { + this.cancelClicked = true; + } +} + +HeroIOComponent.annotations = [ + new Component({ + selector: 'hero-io', + template: ` + + + OK clicked + Cancel clicked + ` + }) +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-lifecycle.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-lifecycle.component.es6 new file mode 100644 index 0000000000..b394ff59aa --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-lifecycle.component.es6 @@ -0,0 +1,15 @@ +// #docregion +import { Component } from '@angular/core'; +export class HeroComponent { + ngOnInit() { + // todo: fetch from server async + setTimeout(() => this.name = 'Windstorm', 0); + } +} + +HeroComponent.annotations = [ + new Component({ + selector: 'hero-lifecycle', + template: `

Hero: {{name}}

` + }) +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-queries.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-queries.component.es6 new file mode 100644 index 0000000000..bf3b914406 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-queries.component.es6 @@ -0,0 +1,97 @@ +import { + Component, + ContentChild, + Input, + QueryList, + ViewChildren +} from '@angular/core'; + +export class ContentChildComponent { + constructor() { + this.active = false; + } + + activate() { + this.active = !this.active; + } +} + +ContentChildComponent.annotations = [ + new Component({ + selector: 'content-child', + template: ` + + Active + ` + }) +]; + +//////////////////// + +// #docregion content +export class ViewChildComponent { + constructor() { + this.active = false; + } + + activate() { + this.active = !this.active; + this.content.activate(); + } +} + +ViewChildComponent.annotations = [ + new Component({ + selector: 'view-child', + template: `

+ {{hero.name}} + +

`, + styles: ['.active {font-weight: bold; background-color: skyblue;}'], + inputs: ['hero'], + queries: { + content: new ContentChild(ContentChildComponent) + } + }) +]; +// #enddocregion content + +//////////////////// + +// #docregion view +export class HeroQueriesComponent { + constructor(){ + this.active = false; + this.heroData = [ + {id: 1, name: 'Windstorm'}, + {id: 2, name: 'LaughingGas'} + ]; + } + + activate() { + this.active = !this.active; + this.views.forEach( + view => view.activate() + ); + } + + get buttonLabel() { + return this.active ? 'Deactivate' : 'Activate'; + } +} + +HeroQueriesComponent.annotations = [ + new Component({ + selector: 'hero-queries', + template: ` + + + + + `, + queries: { + views: new ViewChildren(ViewChildComponent) + } + }) +]; +// #enddocregion view diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-title.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-title.component.es6 new file mode 100644 index 0000000000..ff1e6ce026 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-title.component.es6 @@ -0,0 +1,29 @@ +import { Attribute, Component, Inject, Optional } from '@angular/core'; + +// #docregion +export class HeroTitleComponent { + constructor(titlePrefix, title) { + this.titlePrefix = titlePrefix; + this.title = title; + this.msg = ''; + } + + ok() { + this.msg = 'OK!'; + } +} + +// #docregion templateUrl +HeroTitleComponent.annotations = [ + new Component({ + moduleId: module.id, + selector: 'hero-title', + templateUrl: 'hero-title.component.html' + }) +]; +// #enddocregion templateUrl + +HeroTitleComponent.parameters = [ + [new Optional(), new Inject('titlePrefix')], + [new Attribute('title')] +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-title.component.html b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-title.component.html new file mode 100644 index 0000000000..0e93122d5c --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero-title.component.html @@ -0,0 +1,4 @@ + +

{{titlePrefix}} {{title}}

+ +

{{ msg }}

diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/hero.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero.component.es6 new file mode 100644 index 0000000000..10b92c2878 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/hero.component.es6 @@ -0,0 +1,20 @@ +// #docplaster +// #docregion metadata +import { Component } from '@angular/core'; + +// #docregion appexport, class +export class HeroComponent { + constructor() { + this.title = 'Hero Detail'; + } + getName() {return 'Windstorm'; } +} +// #enddocregion appexport, class + +HeroComponent.annotations = [ + new Component({ + selector: 'hero-view', + template: '

{{title}}: {{getName()}}

' + }) +]; +// #enddocregion metadata diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/app/main.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/app/main.es6 new file mode 100644 index 0000000000..2470c9595e --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/app/main.es6 @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/example-config.json b/public/docs/_examples/cb-ts-to-js/js-es6/example-config.json new file mode 100644 index 0000000000..391bd1a766 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/example-config.json @@ -0,0 +1,4 @@ +{ + "build": "build:babel", + "run": "http-server:e2e" +} \ No newline at end of file diff --git a/public/docs/_examples/upgrade-adapter/ts/index-1-2-hybrid-shared-adapter-bootstrap.html b/public/docs/_examples/cb-ts-to-js/js-es6/index.html similarity index 61% rename from public/docs/_examples/upgrade-adapter/ts/index-1-2-hybrid-shared-adapter-bootstrap.html rename to public/docs/_examples/cb-ts-to-js/js-es6/index.html index 67d9b04e44..1b9e3b5211 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-1-2-hybrid-shared-adapter-bootstrap.html +++ b/public/docs/_examples/cb-ts-to-js/js-es6/index.html @@ -1,12 +1,11 @@ - + - Angular 2 Upgrade + - - + TypeScript to JavaScript @@ -17,12 +16,12 @@ -
{{ mainCtrl.message }}
+ Loading... + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/plnkr.json b/public/docs/_examples/cb-ts-to-js/js-es6/plnkr.json new file mode 100644 index 0000000000..5c7a5acd44 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/plnkr.json @@ -0,0 +1,8 @@ +{ + "description": "TypeScript to JavaScript", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ], + "tags":["cookbook"] +} diff --git a/public/docs/_examples/cb-ts-to-js/js/app/app.component.html b/public/docs/_examples/cb-ts-to-js/js/app/app.component.html new file mode 100644 index 0000000000..6681d60672 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/app.component.html @@ -0,0 +1,47 @@ + +

{{title}}

+Classes and Class Metadata
+Interfaces
+Input and Output Metadata
+Dependency Injection
+Host Metadata
+View and Child Metadata
+ +
+

Classes and Class Metadata

+ +

Classes and Class Metadata (DSL)

+ + +
+

Interfaces

+ +

Interfaces (DSL)

+ + +
+

Input and Output Metadata

+ +

Input and Output Metadata (DSL)

+ + +
+

Dependency Injection

+ + + + +

Dependency Injection (DSL)

+ + + + +
+

Host Metadata

+ +

Host Metadata (DSL)

+ + +
+

View and Child Metadata (DSL)

+ diff --git a/public/docs/_examples/cb-ts-to-js/js/app/app.component.js b/public/docs/_examples/cb-ts-to-js/js/app/app.component.js new file mode 100644 index 0000000000..9e8c5da535 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/app.component.js @@ -0,0 +1,20 @@ +(function(app) { + +app.AppComponent = AppComponent; +function AppComponent() { + this.title = 'ES5 JavaScript'; +} + +AppComponent.annotations = [ + new ng.core.Component({ + selector: 'my-app', + templateUrl: 'app/app.component.html', + styles: [ + // See hero-di-inject-additional.component + 'hero-host, hero-host-dsl { border: 1px dashed black; display: block; padding: 4px;}', + '.heading {font-style: italic}' + ] + }) +]; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/app.module.js b/public/docs/_examples/cb-ts-to-js/js/app/app.module.js new file mode 100644 index 0000000000..3791fe16da --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/app.module.js @@ -0,0 +1,46 @@ +(function(app) { + +app.AppModule = AppModule; +function AppModule() { } + +AppModule.annotations = [ + new ng.core.NgModule({ + imports: [ ng.platformBrowser.BrowserModule ], + declarations: [ + app.AppComponent, + app.ConfirmComponent, app.ConfirmDslComponent, + app.HeroComponent, app.HeroDslComponent, + app.HeroDIComponent, app.HeroDIDslComponent, + app.HeroDIInjectComponent, app.HeroDIInjectDslComponent, + app.HeroDIInjectAdditionalComponent, app.HeroDIInjectAdditionalDslComponent, + app.HeroHostComponent, app.HeroHostDslComponent, + app.HeroIOComponent, app.HeroIODslComponent, + app.HeroLifecycleComponent, app.HeroLifecycleDslComponent, + app.heroQueries.HeroQueriesComponent, app.heroQueries.ViewChildComponent, app.heroQueries.ContentChildComponent, + app.HeroTitleComponent, app.HeroTitleDslComponent + ], + providers: [ + app.DataService, + { provide: 'heroName', useValue: 'Windstorm' } + ], + bootstrap: [ app.AppComponent ], + + // schemas: [ ng.core.NO_ERRORS_SCHEMA ] // helpful for debugging! + }) +] + +})(window.app = window.app || {}); + + +///// For documentation only ///// +(function () { + // #docregion appimport + var HeroComponent = app.HeroComponent; + // #enddocregion appimport + + // #docregion ng2import + var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic; + var LocationStrategy = ng.common.LocationStrategy; + var HashLocationStrategy = ng.common.HashLocationStrategy; + // #enddocregion ng2import +}) diff --git a/public/docs/_examples/cb-ts-to-js/js/app/confirm.component.html b/public/docs/_examples/cb-ts-to-js/js/app/confirm.component.html new file mode 100644 index 0000000000..917bd1696f --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/confirm.component.html @@ -0,0 +1,6 @@ + + diff --git a/public/docs/_examples/cb-ts-to-js/js/app/confirm.component.js b/public/docs/_examples/cb-ts-to-js/js/app/confirm.component.js new file mode 100644 index 0000000000..4a4cd0a470 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/confirm.component.js @@ -0,0 +1,73 @@ +(function(app) { + +// #docregion +app.ConfirmComponent = ConfirmComponent; + +ConfirmComponent.annotations = [ + new ng.core.Component({ + selector: 'app-confirm', + templateUrl: 'app/confirm.component.html', + inputs: [ + 'okMsg', + 'notOkMsg: cancelMsg' + ], + outputs: [ + 'ok', + 'notOk: cancel' + ] + }) +]; + +function ConfirmComponent() { + this.ok = new ng.core.EventEmitter(); + this.notOk = new ng.core.EventEmitter(); +} + +ConfirmComponent.prototype.onOkClick = function() { + this.ok.emit(true); +} + +ConfirmComponent.prototype.onNotOkClick = function() { + this.notOk.emit(true); +} + + +// #enddocregion + +})(window.app = window.app || {}); + +/////// DSL version //////// + +(function(app) { + +// #docregion dsl +app.ConfirmDslComponent = ng.core.Component({ + selector: 'app-confirm-dsl', + templateUrl: 'app/confirm.component.html', + inputs: [ + 'okMsg', + 'notOkMsg: cancelMsg' + ], + outputs: [ + 'ok', + 'notOk: cancel' + ] + }) + .Class({ + constructor: function ConfirmDslComponent() { + this.ok = new ng.core.EventEmitter(); + this.notOk = new ng.core.EventEmitter(); + }, + + onOkClick: function() { + this.ok.emit(true); + }, + + onNotOkClick: function() { + this.notOk.emit(true); + } + }); + +// #enddocregion dsl + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/data.service.js b/public/docs/_examples/cb-ts-to-js/js/app/data.service.js index c060e2b39d..643bb57dca 100644 --- a/public/docs/_examples/cb-ts-to-js/js/app/data.service.js +++ b/public/docs/_examples/cb-ts-to-js/js/app/data.service.js @@ -1,13 +1,10 @@ (function(app) { - function DataService() { - } - DataService.annotations = [ - new ng.core.Injectable() - ]; + app.DataService = DataService; + function DataService() { } + DataService.prototype.getHeroName = function() { return 'Windstorm'; }; - app.DataService = DataService; })(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inject-additional.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inject-additional.component.js index fa9684e7a1..1a88cfa355 100644 --- a/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inject-additional.component.js +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inject-additional.component.js @@ -1,50 +1,26 @@ (function(app) { - // #docregion - var TitleComponent = ng.core.Component({ - selector: 'hero-title', - template: - '

{{titlePrefix}} {{title}}

' + - '' + - '

{{ msg }}

' - }).Class({ - constructor: [ - [ - new ng.core.Optional(), - new ng.core.Inject('titlePrefix') - ], - new ng.core.Attribute('title'), - function(titlePrefix, title) { - this.titlePrefix = titlePrefix; - this.title = title; - this.msg = ''; - } - ], - ok: function() { - this.msg = 'OK!'; - } - }); - // #enddocregion +app.HeroDIInjectAdditionalComponent = HeroDIInjectAdditionalComponent; - var AppComponent = ng.core.Component({ +HeroDIInjectAdditionalComponent.annotations = [ + new ng.core.Component({ selector: 'hero-di-inject-additional', - template: '' + - '' - }).Class({ - constructor: function() { } - }); - - app.HeroesDIInjectAdditionalModule = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - declarations: [ - AppComponent, - TitleComponent - ], - bootstrap: [ AppComponent ] - }) - .Class({ - constructor: function() {} - }); + template: '' + }) +]; + +function HeroDIInjectAdditionalComponent() {} + +})(window.app = window.app || {}); + +////// DSL Version ///////// +(function(app) { + +app.HeroDIInjectAdditionalDslComponent = ng.core.Component({ + selector: 'hero-di-inject-additional-dsl', + template: '' +}).Class({ + constructor: function HeroDIInjectAdditionalDslComponent() { } +}); })(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inject.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inject.component.js index dfda83e1f0..2e04c9246e 100644 --- a/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inject.component.js +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inject.component.js @@ -1,57 +1,41 @@ (function(app) { -// #docregion parameters - function HeroComponent(name) { - this.name = name; - } - HeroComponent.parameters = [ - 'heroName' - ]; - HeroComponent.annotations = [ - new ng.core.Component({ - selector: 'hero-di-inject', - template: '

Hero: {{name}}

' - }) - ]; -// #enddocregion parameters +// #docregion +app.HeroDIInjectComponent = HeroDIInjectComponent; - app.HeroesDIInjectModule = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - providers: [ { provide: 'heroName', useValue: 'Windstorm' } ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] - }) - .Class({ - constructor: function() {} - }); - -})(window.app = window.app || {}); - -(function(app) { -// #docregion ctor - var HeroComponent = ng.core.Component({ - selector: 'hero-di-inline2', +HeroDIInjectComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-di-inject', template: '

Hero: {{name}}

' }) - .Class({ - constructor: - [new ng.core.Inject('heroName'), - function(name) { - this.name = name; - }] - }); -// #enddocregion ctor +]; - app.HeroesDIInjectModule2 = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - providers: [ { provide: 'heroName', useValue: 'Bombasto' } ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] - }) - .Class({ - constructor: function() {} - }); +HeroDIInjectComponent.parameters = [ 'heroName' ]; + +function HeroDIInjectComponent(name) { + this.name = name; +} +// #enddocregion + +})(window.app = window.app || {}); + +/////// DSL version //////// + +(function(app) { + +// #docregion dsl +app.HeroDIInjectDslComponent = ng.core.Component({ + selector: 'hero-di-inject-dsl', + template: '

Hero: {{name}}

' +}) +.Class({ + constructor: [ + new ng.core.Inject('heroName'), + function HeroDIInjectDslComponent(name) { + this.name = name; + } + ] +}); +// #enddocregion dsl })(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inline.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inline.component.js deleted file mode 100644 index 1fe9c38cb1..0000000000 --- a/public/docs/_examples/cb-ts-to-js/js/app/hero-di-inline.component.js +++ /dev/null @@ -1,27 +0,0 @@ -(function(app) { - // #docregion - var HeroComponent = ng.core.Component({ - selector: 'hero-di-inline', - template: '

Hero: {{name}}

' - }) - .Class({ - constructor: - [app.DataService, - function(service) { - this.name = service.getHeroName(); - }] - }); - // #enddocregion - - app.HeroDIInlineModule = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - providers: [ app.DataService ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] - }) - .Class({ - constructor: function() {} - }); - -})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-di.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero-di.component.js index 55c576b836..c80efe193e 100644 --- a/public/docs/_examples/cb-ts-to-js/js/app/hero-di.component.js +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-di.component.js @@ -1,31 +1,43 @@ (function(app) { // #docregion - app.HeroDIComponent = HeroComponent; - - function HeroComponent(dataService) { - this.name = dataService.getHeroName(); - } - HeroComponent.parameters = [ - app.DataService - ]; - HeroComponent.annotations = [ + app.HeroDIComponent = HeroDIComponent; + + HeroDIComponent.annotations = [ new ng.core.Component({ selector: 'hero-di', template: '

Hero: {{name}}

' }) ]; + + HeroDIComponent.parameters = [ app.DataService ]; + + function HeroDIComponent(dataService) { + this.name = dataService.getHeroName(); + } + // #enddocregion - app.HeroesDIModule = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - providers: [ app.DataService ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] - }) - .Class({ - constructor: function() {} - }); + +})(window.app = window.app || {}); + +////// DSL Version ///// + +(function(app) { + +// #docregion dsl +app.HeroDIDslComponent = ng.core.Component({ + selector: 'hero-di-dsl', + template: '

Hero: {{name}}

' +}) +.Class({ + constructor: [ + app.DataService, + function HeroDIDslComponent(service) { + this.name = service.getHeroName(); + } + ] +}); +// #enddocregion dsl })(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-dsl.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero-dsl.component.js deleted file mode 100644 index 5dd84733f3..0000000000 --- a/public/docs/_examples/cb-ts-to-js/js/app/hero-dsl.component.js +++ /dev/null @@ -1,31 +0,0 @@ -// #docplaster -// #docregion appexport -(function(app) { - - // #docregion component - var HeroComponent = ng.core.Component({ - selector: 'hero-view-2', - template: - '

Name: {{getName()}}

', - }) - .Class({ - constructor: function() { - }, - getName: function() { - return 'Windstorm'; - } - }); - // #enddocregion component - - app.HeroesDslModule = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] - }) - .Class({ - constructor: function() {} - }); - -})(window.app = window.app || {}); -// #enddocregion appexport diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-host.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero-host.component.js new file mode 100644 index 0000000000..0b04d5efae --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-host.component.js @@ -0,0 +1,97 @@ +(function(app) { + +// #docregion +app.HeroHostComponent = HeroHostComponent; + +HeroHostComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-host', + template: + '

Hero Host

' + + '
Heading clicks: {{clicks}}
', + host: { + // HostBindings to the element + '[title]': 'title', + '[class.heading]': 'headingClass', + '(click)': 'clicked()', + + // HostListeners on the entire element + '(mouseenter)': 'enter($event)', + '(mouseleave)': 'leave($event)' + }, + // Styles within (but excluding) the element + styles: ['.active {background-color: yellow;}'] + }) +]; + +function HeroHostComponent() { + this.clicks = 0; + this.headingClass = true; + this.title = 'Hero Host Tooltip content'; +} + +HeroHostComponent.prototype.clicked = function() { + this.clicks += 1; +} + +HeroHostComponent.prototype.enter = function(event) { + this.active = true; + this.headingClass = false; +} + +HeroHostComponent.prototype.leave = function(event) { + this.active = false; + this.headingClass = true; +} +// #enddocregion + +})(window.app = window.app || {}); + +//// DSL Version //// + +(function(app) { + +// #docregion dsl +app.HeroHostDslComponent = ng.core.Component({ + selector: 'hero-host-dsl', + template: ` +

Hero Host (DSL)

+
Heading clicks: {{clicks}}
+ `, + host: { + // HostBindings to the element + '[title]': 'title', + '[class.heading]': 'headingClass', + '(click)': 'clicked()', + + // HostListeners on the entire element + '(mouseenter)': 'enter($event)', + '(mouseleave)': 'leave($event)' + }, + // Styles within (but excluding) the element + styles: ['.active {background-color: coral;}'] +}) +.Class({ + constructor: function HeroHostDslComponent() { + this.clicks = 0; + this.headingClass = true; + this.title = 'Hero Host Tooltip DSL content'; + }, + + clicked() { + this.clicks += 1; + }, + + enter(event) { + this.active = true; + this.headingClass = false; + }, + + leave(event) { + this.active = false; + this.headingClass = true; + } +}); +// #enddocregion dsl + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-io-dsl.component.html b/public/docs/_examples/cb-ts-to-js/js/app/hero-io-dsl.component.html new file mode 100644 index 0000000000..48c491be35 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-io-dsl.component.html @@ -0,0 +1,7 @@ + + +OK clicked +Cancel clicked diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-io.component.html b/public/docs/_examples/cb-ts-to-js/js/app/hero-io.component.html new file mode 100644 index 0000000000..e6eae2e804 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-io.component.html @@ -0,0 +1,7 @@ + + +OK clicked +Cancel clicked diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-io.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero-io.component.js index 79aef12125..d35f3762da 100644 --- a/public/docs/_examples/cb-ts-to-js/js/app/hero-io.component.js +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-io.component.js @@ -1,68 +1,42 @@ (function(app) { - // #docregion - var ConfirmComponent = ng.core.Component({ - selector: 'my-confirm', - inputs: [ - 'okMsg', - 'notOkMsg: cancelMsg' - ], - outputs: [ - 'ok', - 'notOk: cancel' - ], - template: - '' + - '' - }).Class({ - constructor: function() { - this.ok = new ng.core.EventEmitter(); - this.notOk = new ng.core.EventEmitter(); - }, - onOkClick: function() { - this.ok.next(true); - }, - onNotOkClick: function() { - this.notOk.next(true); - } - }); - // #enddocregion - function AppComponent() { - } - AppComponent.annotations = [ - new ng.core.Component({ - selector: 'hero-io', - template: '' + - '' + - 'OK clicked' + - 'Cancel clicked' - }) - ]; - AppComponent.prototype.onOk = function() { - this.okClicked = true; - } - AppComponent.prototype.onCancel = function() { - this.cancelClicked = true; - } +app.HeroIOComponent = HeroComponent; - app.HeroesIOModule = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - declarations: [ - AppComponent, - ConfirmComponent - ], - bootstrap: [ AppComponent ] - }) - .Class({ - constructor: function() {} - }); +HeroComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-io', + templateUrl: 'app/hero-io.component.html' + }) +]; + +function HeroComponent() { } + +HeroComponent.prototype.onOk = function() { + this.okClicked = true; +} + +HeroComponent.prototype.onCancel = function() { + this.cancelClicked = true; +} + +})(window.app = window.app || {}); + +///// DSL Version //// + +(function(app) { + +app.HeroIODslComponent = ng.core.Component({ + selector: 'hero-io-dsl', + templateUrl: 'app/hero-io-dsl.component.html' + }) + .Class({ + constructor: function HeroIODslComponent() { }, + onOk: function() { + this.okClicked = true; + }, + onCancel: function() { + this.cancelClicked = true; + } + }); })(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-lifecycle.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero-lifecycle.component.js index 3e81c72e4e..94aa3514b2 100644 --- a/public/docs/_examples/cb-ts-to-js/js/app/hero-lifecycle.component.js +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-lifecycle.component.js @@ -1,29 +1,42 @@ // #docplaster (function(app) { - // #docregion - function HeroComponent() {} - // #enddocregion - HeroComponent.annotations = [ - new ng.core.Component({ - selector: 'hero-lifecycle', - template: '

Hero: {{name}}

' - }) - ]; - // #docregion - HeroComponent.prototype.ngOnInit = - function() { - this.name = 'Windstorm'; - }; - // #enddocregion - app.HeroesLifecycleModule = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] - }) - .Class({ - constructor: function() {} - }); +// #docregion +app.HeroLifecycleComponent = HeroComponent; + +HeroComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-lifecycle', + template: '

Hero: {{name}}

' + }) +]; + +function HeroComponent() { } + +HeroComponent.prototype.ngOnInit = function() { + // todo: fetch from server async + setTimeout(() => this.name = 'Windstorm', 0); +}; +// #enddocregion + +})(window.app = window.app || {}); + +/////// DSL version //// + +(function(app) { + +// #docregion dsl +app.HeroLifecycleDslComponent = ng.core.Component({ + selector: 'hero-lifecycle-dsl', + template: '

Hero: {{name}}

' + }) + .Class({ + constructor: function HeroLifecycleDslComponent() { }, + ngOnInit: function() { + // todo: fetch from server async + setTimeout(() => this.name = 'Windstorm', 0); + } + }); +// #enddocregion dsl })(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-queries.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero-queries.component.js new file mode 100644 index 0000000000..5e21cfcb0b --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-queries.component.js @@ -0,0 +1,92 @@ +(function(app) { + +app.heroQueries = app.heroQueries || {}; + +app.heroQueries.ContentChildComponent = ng.core.Component({ + selector: 'content-child', + template: + '' + + 'Active' + + '' +}).Class({ + constructor: function ContentChildComponent() { + this.active = false; + }, + + activate: function() { + this.active = !this.active; + } +}); + +//////////////////// + +// #docregion content +app.heroQueries.ViewChildComponent = ng.core.Component({ + selector: 'view-child', + template: + '

' + + '{{hero.name}} ' + + '' + + '

', + styles: ['.active {font-weight: bold; background-color: skyblue;}'], + inputs: ['hero'], + queries: { + content: new ng.core.ContentChild(app.heroQueries.ContentChildComponent) + } +}) +.Class({ + constructor: function HeroQueriesHeroComponent() { + this.active = false; + }, + + activate: function() { + this.active = !this.active; + this.content.activate(); + } +}); +// #enddocregion content + +//////////////////// + +// #docregion view +app.heroQueries.HeroQueriesComponent = ng.core.Component({ + selector: 'hero-queries', + template: + '' + + '' + + '' + + '', + queries: { + views: new ng.core.ViewChildren(app.heroQueries.ViewChildComponent) + } +}) +.Class({ + constructor: function HeroQueriesComponent() { + this.active = false; + this.heroData = [ + {id: 1, name: 'Windstorm'}, + {id: 2, name: 'LaughingGas'} + ]; + }, + + activate: function() { + this.active = !this.active; + this.views.forEach(function(view) { + view.activate(); + }); + }, +}); + +// #docregion defined-property +// add prototype property w/ getter outside the DSL +var proto = app.heroQueries.HeroQueriesComponent.prototype; +Object.defineProperty(proto, "buttonLabel", { + get: function () { + return this.active ? 'Deactivate' : 'Activate'; + }, + enumerable: true +}); +// #enddocregion defined-property +// #enddocregion view + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-title.component.html b/public/docs/_examples/cb-ts-to-js/js/app/hero-title.component.html new file mode 100644 index 0000000000..0e93122d5c --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-title.component.html @@ -0,0 +1,4 @@ + +

{{titlePrefix}} {{title}}

+ +

{{ msg }}

diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero-title.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero-title.component.js new file mode 100644 index 0000000000..9a8ce7e578 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero-title.component.js @@ -0,0 +1,60 @@ +(function(app) { + +// #docregion +app.HeroTitleComponent = HeroTitleComponent; + +// #docregion templateUrl +HeroTitleComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-title', + templateUrl: 'app/hero-title.component.html' + }) +]; +// #enddocregion templateUrl + +function HeroTitleComponent(titlePrefix, title) { + this.titlePrefix = titlePrefix; + this.title = title; + this.msg = ''; +} + +HeroTitleComponent.prototype.ok = function() { + this.msg = 'OK!'; +} + +HeroTitleComponent.parameters = [ + [new ng.core.Optional(), new ng.core.Inject('titlePrefix')], + [new ng.core.Attribute('title')] +]; + +// #enddocregion + +})(window.app = window.app || {}); + +////////// DSL version //////////// + +(function(app) { + +// #docregion dsl +app.HeroTitleDslComponent = ng.core.Component({ + selector: 'hero-title-dsl', + templateUrl: 'app/hero-title.component.html' +}) +.Class({ + constructor: [ + [ new ng.core.Optional(), new ng.core.Inject('titlePrefix') ], + new ng.core.Attribute('title'), + function HeroTitleDslComponent(titlePrefix, title) { + this.titlePrefix = titlePrefix; + this.title = title; + this.msg = ''; + } + ], + + ok: function() { + this.msg = 'OK!'; + } +}); +// #enddocregion dsl + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/hero.component.js b/public/docs/_examples/cb-ts-to-js/js/app/hero.component.js index c6a58acc56..346d6f03d8 100644 --- a/public/docs/_examples/cb-ts-to-js/js/app/hero.component.js +++ b/public/docs/_examples/cb-ts-to-js/js/app/hero.component.js @@ -1,42 +1,48 @@ // #docplaster -// #docregion appexport (function(app) { - // #enddocregion appexport - // #docregion metadata - // #docregion appexport - // #docregion constructorproto - function HeroComponent() { - this.title = "Hero Detail"; - } - - // #enddocregion constructorproto - // #enddocregion appexport - HeroComponent.annotations = [ - new ng.core.Component({ - selector: 'hero-view', - template: - '

Hero: {{getName()}}

' - }) - ]; - // #docregion constructorproto - HeroComponent.prototype.getName = - function() {return 'Windstorm';}; - // #enddocregion constructorproto - // #enddocregion metadata +// #docregion +// #docregion appexport +// #docregion metadata +app.HeroComponent = HeroComponent; // "export" - app.HeroesModule = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] - }) - .Class({ - constructor: function() {} - }); +HeroComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-view', + template: '

{{title}}: {{getName()}}

' + }) +]; - // #docregion appexport - app.HeroComponent = HeroComponent; +// #docregion constructorproto +function HeroComponent() { + this.title = "Hero Detail"; +} + +HeroComponent.prototype.getName = function() { return 'Windstorm'; }; +// #enddocregion constructorproto + +// #enddocregion metadata +// #enddocregion appexport +// #enddocregion + +})(window.app = window.app || {}); + +//////////// DSL version /////////// + +(function(app) { + +// #docregion dsl +app.HeroDslComponent = ng.core.Component({ + selector: 'hero-view-dsl', + template: '

{{title}}: {{getName()}}

', + }) + .Class({ + constructor: function HeroDslComponent() { + this.title = "Hero Detail"; + }, + + getName: function() { return 'Windstorm'; } + }); +// #enddocregion dsl })(window.app = window.app || {}); -// #enddocregion appexport diff --git a/public/docs/_examples/cb-ts-to-js/js/app/heroes-bindings.component.js b/public/docs/_examples/cb-ts-to-js/js/app/heroes-bindings.component.js deleted file mode 100644 index 3a562d6912..0000000000 --- a/public/docs/_examples/cb-ts-to-js/js/app/heroes-bindings.component.js +++ /dev/null @@ -1,39 +0,0 @@ -(function(app) { - - // #docregion - var HeroesComponent = ng.core.Component({ - selector: 'heroes-bindings', - template: '

' + - 'Tour of Heroes' + - '

', - host: { - '[title]': 'title', - '[class.heading]': 'hClass', - '(click)': 'clicked()', - '(dblclick)': 'doubleClicked($event)' - } - }).Class({ - constructor: function() { - this.title = 'Tooltip content'; - this.hClass = true; - }, - clicked: function() { - this.active = !this.active; - }, - doubleClicked: function(evt) { - this.active = true; - } - }); - // #enddocregion - - app.HeroesHostBindingsModule = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - declarations: [ HeroesComponent ], - bootstrap: [ HeroesComponent ] - }) - .Class({ - constructor: function() {} - }); - -})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/heroes-queries.component.js b/public/docs/_examples/cb-ts-to-js/js/app/heroes-queries.component.js deleted file mode 100644 index f1bda77cb1..0000000000 --- a/public/docs/_examples/cb-ts-to-js/js/app/heroes-queries.component.js +++ /dev/null @@ -1,82 +0,0 @@ -(function(app) { - - var ActiveLabelComponent = ng.core.Component({ - selector: 'active-label', - template: '' + - 'Active' + - '' - }).Class({ - constructor: [function() { }], - activate: function() { - this.active = true; - } - }); - - // #docregion content - var HeroComponent = ng.core.Component({ - selector: 'a-hero', - template: '

' + - '{{hero.name}} ' + - '' + - '

', - inputs: ['hero'], - queries: { - label: new ng.core.ContentChild( - ActiveLabelComponent) - } - }).Class({ - constructor: [function() { }], - activate: function() { - this.active = true; - this.label.activate(); - } - }); - app.HeroQueriesComponent = HeroComponent; - // #enddocregion content - - // #docregion view - var AppComponent = ng.core.Component({ - selector: 'heroes-queries', - template: - '' + - '' + - '' + - '', - queries: { - heroCmps: new ng.core.ViewChildren( - HeroComponent) - } - }).Class({ - constructor: function() { - this.heroData = [ - {id: 1, name: 'Windstorm'}, - {id: 2, name: 'Superman'} - ]; - }, - activate: function() { - this.heroCmps.forEach(function(cmp) { - cmp.activate(); - }); - } - }); - // #enddocregion view - - app.HeroesQueriesModule = - ng.core.NgModule({ - imports: [ ng.platformBrowser.BrowserModule ], - declarations: [ - AppComponent, - HeroComponent, - ActiveLabelComponent - ], - bootstrap: [ AppComponent ] - }) - .Class({ - constructor: function() {} - }); - -})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/app/main.js b/public/docs/_examples/cb-ts-to-js/js/app/main.js index 9091452599..fd3e737c9e 100644 --- a/public/docs/_examples/cb-ts-to-js/js/app/main.js +++ b/public/docs/_examples/cb-ts-to-js/js/app/main.js @@ -1,35 +1,9 @@ -// #docplaster -// #docregion appimport (function(app) { - // #enddocregion appimport - // #docregion ng2import - var platformBrowserDynamic = - ng.platformBrowserDynamic.platformBrowserDynamic; - var LocationStrategy = - ng.common.LocationStrategy; - var HashLocationStrategy = - ng.common.HashLocationStrategy; - // #enddocregion ng2import +var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic; - // #docregion appimport - var HeroComponent = app.HeroComponent; - // #enddocregion appimport +document.addEventListener('DOMContentLoaded', function() { + platformBrowserDynamic().bootstrapModule(app.AppModule); +}); - document.addEventListener('DOMContentLoaded', function() { - platformBrowserDynamic().bootstrapModule(app.HeroesModule); - platformBrowserDynamic().bootstrapModule(app.HeroesDslModule); - platformBrowserDynamic().bootstrapModule(app.HeroesLifecycleModule); - platformBrowserDynamic().bootstrapModule(app.HeroesDIModule); - platformBrowserDynamic().bootstrapModule(app.HeroDIInlineModule); - platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectModule); - platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectModule2); - platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectAdditionalModule); - platformBrowserDynamic().bootstrapModule(app.HeroesIOModule); - platformBrowserDynamic().bootstrapModule(app.HeroesHostBindingsModule); - platformBrowserDynamic().bootstrapModule(app.HeroesQueriesModule); - }); - - // #docregion appimport })(window.app = window.app || {}); -// #enddocregion appimport diff --git a/public/docs/_examples/cb-ts-to-js/js/index.html b/public/docs/_examples/cb-ts-to-js/js/index.html index 448c295609..7d2105bf78 100644 --- a/public/docs/_examples/cb-ts-to-js/js/index.html +++ b/public/docs/_examples/cb-ts-to-js/js/index.html @@ -4,64 +4,41 @@ + TypeScript to JavaScript + - + + + - - - - - + + + + + + - -

TypeScript to JavaScript

- Classes and Class Metadata
- Input and Output Metadata
- Dependency Injection
- Host and Query Metadata
- -
-

Classes and Class Metadata

- Loading hero-view... - Loading hero-view2... - Loading hero-lifecycle... - -
-

Input and Output Metadata

- Loading hero-io... - -
-

Dependency Injection

- Loading hero-di... - Loading hero-di-inline... - Loading hero-di-inline2... - Loading hero-di-inject... - Loading hero-di-inject-additional... - -
-

Host and Query Metadata

- Loading heroes-bindings... - Loading heroes-queries... + Loading... diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/app.component.html b/public/docs/_examples/cb-ts-to-js/ts/app/app.component.html new file mode 100644 index 0000000000..7f1efd31a0 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/app/app.component.html @@ -0,0 +1,31 @@ + +

{{title}}

+Classes and Class Metadata
+Input and Output Decorators
+Dependency Injection
+Host Metadata
+View and Child Metadata
+ +
+

Classes and Class Metadata

+ + + +
+

Input and Output Metadata

+ + +
+

Dependency Injection

+ + + + +
+

Host Metadata

+ + + +
+

View and Child Metadata

+ diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/app.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/app.component.ts new file mode 100644 index 0000000000..722d812f63 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/app/app.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: 'my-app', + templateUrl: 'app.component.html', + styles: [ + // See hero-di-inject-additional.component + 'hero-host, hero-host-meta { border: 1px dashed black; display: block; padding: 4px;}', + '.heading {font-style: italic}' + ] +}) +export class AppComponent { + title = 'TypeScript'; +} diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/app.module.ts b/public/docs/_examples/cb-ts-to-js/ts/app/app.module.ts new file mode 100644 index 0000000000..8aafe9c9bb --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/app/app.module.ts @@ -0,0 +1,56 @@ +/* tslint:disable-next-line:no-unused-variable */ +import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { ConfirmComponent } from './confirm.component'; +// #docregion appimport +import { HeroComponent } from './hero.component'; +// #enddocregion appimport +import { HeroComponent as HeroDIComponent } from './hero-di.component'; +import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component'; +import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component'; +import { HeroHostComponent } from './hero-host.component'; +import { HeroHostMetaComponent } from './hero-host-meta.component'; +import { HeroIOComponent } from './hero-io.component'; +import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component'; +import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component'; +import { HeroTitleComponent } from './hero-title.component'; + +import { DataService } from './data.service'; + +@NgModule({ + imports: [ + BrowserModule + ], + declarations: [ + AppComponent, + ConfirmComponent, + HeroComponent, + HeroDIComponent, + HeroDIInjectComponent, + HeroDIInjectAdditionalComponent, + HeroHostComponent, HeroHostMetaComponent, + HeroIOComponent, + HeroLifecycleComponent, + HeroQueriesComponent, ViewChildComponent, ContentChildComponent, + HeroTitleComponent + ], + providers: [ + DataService, + { provide: 'heroName', useValue: 'Windstorm' } + ], + bootstrap: [ AppComponent ], + + // schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging! +}) +export class AppModule { } + +/* tslint:disable no-unused-variable */ +// #docregion ng2import +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { + LocationStrategy, + HashLocationStrategy +} from '@angular/common'; +// #enddocregion ng2import diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/confirm.component.html b/public/docs/_examples/cb-ts-to-js/ts/app/confirm.component.html new file mode 100644 index 0000000000..917bd1696f --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/app/confirm.component.html @@ -0,0 +1,6 @@ + + diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/confirm.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/confirm.component.ts new file mode 100644 index 0000000000..08a0ed6c60 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/app/confirm.component.ts @@ -0,0 +1,22 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +// #docregion +@Component({ + moduleId: module.id, + selector: 'app-confirm', + templateUrl: 'confirm.component.html' +}) +export class ConfirmComponent { + @Input() okMsg = ''; + @Input('cancelMsg') notOkMsg = ''; + @Output() ok = new EventEmitter(); + @Output('cancel') notOk = new EventEmitter(); + + onOkClick() { + this.ok.emit(true); + } + onNotOkClick() { + this.notOk.emit(true); + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/data.service.ts b/public/docs/_examples/cb-ts-to-js/ts/app/data.service.ts index 7e9c7456c6..cd7f9e1aae 100644 --- a/public/docs/_examples/cb-ts-to-js/ts/app/data.service.ts +++ b/public/docs/_examples/cb-ts-to-js/ts/app/data.service.ts @@ -2,8 +2,8 @@ import { Injectable } from '@angular/core'; @Injectable() export class DataService { - constructor() { - } + constructor() { } + getHeroName() { return 'Windstorm'; } diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero-di-inject-additional.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/hero-di-inject-additional.component.ts index 146c6cbd83..ec460a9dbc 100644 --- a/public/docs/_examples/cb-ts-to-js/ts/app/hero-di-inject-additional.component.ts +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero-di-inject-additional.component.ts @@ -1,50 +1,7 @@ -import { - Attribute, - Component, - Inject, - Optional, - NgModule -} from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -// #docregion -@Component({ - selector: 'hero-title', - template: ` -

{{titlePrefix}} {{title}}

- -

{{ msg }}

- ` -}) -class TitleComponent { - private msg: string = ''; - constructor( - @Inject('titlePrefix') - @Optional() - private titlePrefix: string, - @Attribute('title') - private title: string) { - } - - ok() { - this.msg = 'OK!'; - } -} -// #enddocregion +import { Component } from '@angular/core'; @Component({ selector: 'hero-di-inject-additional', - template: ` - ` + template: `` }) -class AppComponent { } - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ - AppComponent, - TitleComponent - ], - bootstrap: [ AppComponent ] -}) -export class HeroesDIInjectAdditionalModule { } +export class HeroComponent { } diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero-di-inject.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/hero-di-inject.component.ts index 7dc2bc84a2..c583a1b0f6 100644 --- a/public/docs/_examples/cb-ts-to-js/ts/app/hero-di-inject.component.ts +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero-di-inject.component.ts @@ -1,23 +1,11 @@ -import { Component, Inject, NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; +import { Component, Inject } from '@angular/core'; // #docregion @Component({ selector: 'hero-di-inject', template: `

Hero: {{name}}

` }) -class HeroComponent { - constructor( - @Inject('heroName') - private name: string) { - } +export class HeroComponent { + constructor(@Inject('heroName') private name: string) { } } // #enddocregion - -@NgModule({ - imports: [ BrowserModule ], - providers: [ { provide: 'heroName', useValue: 'Windstorm' } ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] -}) -export class HeroesDIInjectModule { } diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero-di.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/hero-di.component.ts index a20453ef0a..0cc78d277e 100644 --- a/public/docs/_examples/cb-ts-to-js/ts/app/hero-di.component.ts +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero-di.component.ts @@ -1,6 +1,4 @@ -import { Component, NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - +import { Component } from '@angular/core'; import { DataService } from './data.service'; // #docregion @@ -8,18 +6,10 @@ import { DataService } from './data.service'; selector: 'hero-di', template: `

Hero: {{name}}

` }) -class HeroComponent { - name: string; +export class HeroComponent { + name = ''; constructor(dataService: DataService) { this.name = dataService.getHeroName(); } } // #enddocregion - -@NgModule({ - imports: [ BrowserModule ], - providers: [ DataService ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] -}) -export class HeroesDIModule { } diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero-host-meta.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/hero-host-meta.component.ts new file mode 100644 index 0000000000..fefe4a5470 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero-host-meta.component.ts @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-host-meta', + template: ` +

Hero Host in Metadata

+
Heading clicks: {{clicks}}
+ `, + host: { + // HostBindings to the element + '[title]': 'title', + '[class.heading]': 'headingClass', + + // HostListeners on the entire element + '(click)': 'clicked()', + '(mouseenter)': 'enter($event)', + '(mouseleave)': 'leave($event)' + }, + // Styles within (but excluding) the element + styles: ['.active {background-color: coral;}'] +}) +export class HeroHostMetaComponent { + title = 'Hero Host in Metadata Tooltip'; + headingClass = true; + + active = false; + clicks = 0; + + clicked() { + this.clicks += 1; + } + + enter(event: Event) { + this.active = true; + this.headingClass = false; + } + + leave(event: Event) { + this.active = false; + this.headingClass = true; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero-host.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/hero-host.component.ts new file mode 100644 index 0000000000..e8d72233c8 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero-host.component.ts @@ -0,0 +1,39 @@ +import { Component, HostBinding, HostListener } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-host', + template: ` +

Hero Host in Decorators

+
Heading clicks: {{clicks}}
+ `, + // Styles within (but excluding) the element + styles: ['.active {background-color: yellow;}'] +}) +export class HeroHostComponent { + // HostBindings to the element + @HostBinding() title = 'Hero Host in Decorators Tooltip'; + @HostBinding('class.heading') headingClass = true; + + active = false; + clicks = 0; + + // HostListeners on the entire element + @HostListener('click') + clicked() { + this.clicks += 1; + } + + @HostListener('mouseenter', ['$event']) + enter(event: Event) { + this.active = true; + this.headingClass = false; + } + + @HostListener('mouseleave', ['$event']) + leave(event: Event) { + this.active = false; + this.headingClass = true; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero-io.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/hero-io.component.ts index 8cf430c000..4b36411e78 100644 --- a/public/docs/_examples/cb-ts-to-js/ts/app/hero-io.component.ts +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero-io.component.ts @@ -1,73 +1,26 @@ -import { - Component, - EventEmitter, - Input, - Output, - NgModule -} from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -// #docregion -@Component({ - selector: 'my-confirm', - template: ` - - - ` -}) -class ConfirmComponent { - @Input() okMsg: string; - @Input('cancelMsg') notOkMsg: string; - @Output() ok = - new EventEmitter(); - @Output('cancel') notOk = - new EventEmitter(); - - onOkClick() { - this.ok.next(true); - } - onNotOkClick() { - this.notOk.next(true); - } -} -// #enddocregion - +import { Component } from '@angular/core'; @Component({ selector: 'hero-io', template: ` - - + + OK clicked Cancel clicked ` }) -class AppComponent { - okClicked: boolean; - cancelClicked: boolean; +export class HeroIOComponent { + okClicked = false; + cancelClicked = false; onOk() { this.okClicked = true; } + onCancel() { this.cancelClicked = true; } } - - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ - AppComponent, - ConfirmComponent - ], - bootstrap: [ AppComponent ] -}) -export class HeroesIOModule { } diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero-lifecycle.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/hero-lifecycle.component.ts index 1181c71cc9..2629c85a1a 100644 --- a/public/docs/_examples/cb-ts-to-js/ts/app/hero-lifecycle.component.ts +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero-lifecycle.component.ts @@ -1,28 +1,14 @@ -// #docplaster // #docregion import { Component, OnInit } from '@angular/core'; -// #enddocregion -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; @Component({ selector: 'hero-lifecycle', template: `

Hero: {{name}}

` }) -// #docregion -class HeroComponent - implements OnInit { +export class HeroComponent implements OnInit { name: string; ngOnInit() { - this.name = 'Windstorm'; + // todo: fetch from server async + setTimeout(() => this.name = 'Windstorm', 0); } } -// #enddocregion - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] -}) -export class HeroesLifecycleModule { } - diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero-queries.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/hero-queries.component.ts new file mode 100644 index 0000000000..8b2d91ea85 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero-queries.component.ts @@ -0,0 +1,83 @@ +import { + Component, + ContentChild, + Input, + QueryList, + ViewChildren +} from '@angular/core'; + +@Component({ + selector: 'content-child', + template: ` + + Active + ` +}) +export class ContentChildComponent { + active = false; + + activate() { + this.active = !this.active; + } +} + +//////////////////// + +// #docregion content +@Component({ + selector: 'view-child', + template: ` +

+ {{hero.name}} + +

`, + styles: ['.active {font-weight: bold; background-color: skyblue;}'] +}) +export class ViewChildComponent { + @Input() hero: any; + active = false; + + @ContentChild(ContentChildComponent) content: ContentChildComponent; + + activate() { + this.active = !this.active; + this.content.activate(); + } +} +// #enddocregion content + +//////////////////// + +// #docregion view +@Component({ + selector: 'hero-queries', + template: ` + + + + + ` +}) +export class HeroQueriesComponent { + active = false; + heroData = [ + {id: 1, name: 'Windstorm'}, + {id: 2, name: 'LaughingGas'} + ]; + + @ViewChildren(ViewChildComponent) views: QueryList; + + activate() { + this.active = !this.active; + this.views.forEach( + view => view.activate() + ); + } + + // #docregion defined-property + get buttonLabel() { + return this.active ? 'Deactivate' : 'Activate'; + } + // #enddocregion defined-property +} +// #enddocregion view diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero-title.component.html b/public/docs/_examples/cb-ts-to-js/ts/app/hero-title.component.html new file mode 100644 index 0000000000..0e93122d5c --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero-title.component.html @@ -0,0 +1,4 @@ + +

{{titlePrefix}} {{title}}

+ +

{{ msg }}

diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero-title.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/hero-title.component.ts new file mode 100644 index 0000000000..074f2edd61 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero-title.component.ts @@ -0,0 +1,22 @@ +import { Attribute, Component, Inject, Optional } from '@angular/core'; + +// #docregion +// #docregion templateUrl +@Component({ + moduleId: module.id, + selector: 'hero-title', + templateUrl: 'hero-title.component.html' +}) +// #enddocregion templateUrl +export class HeroTitleComponent { + msg: string = ''; + constructor( + @Inject('titlePrefix') @Optional() private titlePrefix: string, + @Attribute('title') private title: string + ) { } + + ok() { + this.msg = 'OK!'; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/hero.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/hero.component.ts index 4b4ba8529d..4ea4c11611 100644 --- a/public/docs/_examples/cb-ts-to-js/ts/app/hero.component.ts +++ b/public/docs/_examples/cb-ts-to-js/ts/app/hero.component.ts @@ -1,30 +1,14 @@ -// #docplaster // #docregion metadata import { Component } from '@angular/core'; @Component({ selector: 'hero-view', - template: - '

Hero: {{getName()}}

' + template: '

{{title}}: {{getName()}}

' }) -// #docregion appexport -// #docregion class +// #docregion appexport, class export class HeroComponent { title = 'Hero Detail'; getName() {return 'Windstorm'; } } -// #enddocregion class -// #enddocregion appexport +// #enddocregion appexport, class // #enddocregion metadata - -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ HeroComponent ], - bootstrap: [ HeroComponent ] -}) -export class HeroesModule { } - - diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/heroes-bindings.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/heroes-bindings.component.ts deleted file mode 100644 index 407b8b0e29..0000000000 --- a/public/docs/_examples/cb-ts-to-js/ts/app/heroes-bindings.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { - Component, - HostBinding, - HostListener, - NgModule -} from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -// #docregion -@Component({ - selector: 'heroes-bindings', - template: `

- Tour of Heroes -

` -}) -class HeroesComponent { - @HostBinding() title = 'Tooltip content'; - @HostBinding('class.heading') - hClass = true; - active: boolean; - - constructor() {} - - @HostListener('click') - clicked() { - this.active = !this.active; - } - - @HostListener('dblclick', ['$event']) - doubleClicked(evt: Event) { - this.active = true; - } -} -// #enddocregion - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ HeroesComponent ], - bootstrap: [ HeroesComponent ] -}) -export class HeroesHostBindingsModule { } diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/heroes-queries.component.ts b/public/docs/_examples/cb-ts-to-js/ts/app/heroes-queries.component.ts deleted file mode 100644 index 97003766e6..0000000000 --- a/public/docs/_examples/cb-ts-to-js/ts/app/heroes-queries.component.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { - Component, - ViewChildren, - ContentChild, - QueryList, - Input, - NgModule -} from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -@Component({ - selector: 'active-label', - template: ` - Active - ` -}) -class ActiveLabelComponent { - active: boolean; - - activate() { - this.active = true; - } -} - -// #docregion content -@Component({ - selector: 'a-hero', - template: `

- {{hero.name}} - -

` -}) -class HeroComponent { - @Input() hero: any; - active: boolean; - - @ContentChild(ActiveLabelComponent) - label: ActiveLabelComponent; - - activate() { - this.active = true; - this.label.activate(); - } -} -// #enddocregion content - - -// #docregion view -@Component({ - selector: 'heroes-queries', - template: ` - - - - - ` -}) -class HeroesQueriesComponent { - heroData = [ - {id: 1, name: 'Windstorm'}, - {id: 2, name: 'Superman'} - ]; - - @ViewChildren(HeroComponent) - heroCmps: QueryList; - - activate() { - this.heroCmps.forEach( - (cmp) => cmp.activate() - ); - } -} -// #enddocregion view - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ - HeroesQueriesComponent, - HeroComponent, - ActiveLabelComponent - ], - bootstrap: [ HeroesQueriesComponent ] -}) -export class HeroesQueriesModule { } diff --git a/public/docs/_examples/cb-ts-to-js/ts/app/main.ts b/public/docs/_examples/cb-ts-to-js/ts/app/main.ts index 92f5af5e1a..7cc80b5964 100644 --- a/public/docs/_examples/cb-ts-to-js/ts/app/main.ts +++ b/public/docs/_examples/cb-ts-to-js/ts/app/main.ts @@ -1,30 +1,4 @@ -/* tslint:disable no-unused-variable */ -// #docregion ng2import -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; -import { - LocationStrategy, - HashLocationStrategy -} from '@angular/common'; -// #enddocregion ng2import - -// #docregion appimport -import { HeroComponent } from './hero.component'; -// #enddocregion appimport - -import { HeroesModule } from './hero.component'; -import { HeroesLifecycleModule } from './hero-lifecycle.component'; -import { HeroesDIModule } from './hero-di.component'; -import { HeroesDIInjectModule } from './hero-di-inject.component'; -import { HeroesDIInjectAdditionalModule } from './hero-di-inject-additional.component'; -import { HeroesIOModule } from './hero-io.component'; -import { HeroesHostBindingsModule } from './heroes-bindings.component'; -import { HeroesQueriesModule } from './heroes-queries.component'; - -platformBrowserDynamic().bootstrapModule(HeroesModule); -platformBrowserDynamic().bootstrapModule(HeroesLifecycleModule); -platformBrowserDynamic().bootstrapModule(HeroesDIModule); -platformBrowserDynamic().bootstrapModule(HeroesDIInjectModule); -platformBrowserDynamic().bootstrapModule(HeroesDIInjectAdditionalModule); -platformBrowserDynamic().bootstrapModule(HeroesIOModule); -platformBrowserDynamic().bootstrapModule(HeroesHostBindingsModule); -platformBrowserDynamic().bootstrapModule(HeroesQueriesModule); +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-ts-to-js/ts/index.html b/public/docs/_examples/cb-ts-to-js/ts/index.html index 005fe67c31..5791134d4f 100644 --- a/public/docs/_examples/cb-ts-to-js/ts/index.html +++ b/public/docs/_examples/cb-ts-to-js/ts/index.html @@ -5,8 +5,9 @@ + TypeScript to JavaScript - + @@ -20,32 +21,7 @@ - -

TypeScript to JavaScript

- Classes and Class Metadata
- Input and Output Metadata
- Dependency Injection
- Host and Query Metadata
- -
-

Classes and Class Metadata

- Loading hero-view... - Loading hero-lifecycle... - -
-

Input and Output Metadata

- Loading hero-io... - -
-

Dependency Injection

- Loading hero-di... - Loading hero-di-inject... - Loading hero-di-inject-additional... - -
-

Host and Query Metadata

- Loading heroes-bindings... - Loading heroes-queries... + Loading... diff --git a/public/docs/_examples/component-styles/dart/pubspec.yaml b/public/docs/_examples/component-styles/dart/pubspec.yaml index 5b129ec698..66b148a5ef 100755 --- a/public/docs/_examples/component-styles/dart/pubspec.yaml +++ b/public/docs/_examples/component-styles/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/component-styles/ts/index.html b/public/docs/_examples/component-styles/ts/index.html index 9345f5b221..115e5b9299 100644 --- a/public/docs/_examples/component-styles/ts/index.html +++ b/public/docs/_examples/component-styles/ts/index.html @@ -6,7 +6,7 @@ - + diff --git a/public/docs/_examples/dependency-injection/dart/lib/app_component.dart b/public/docs/_examples/dependency-injection/dart/lib/app_component.dart index cb29545084..5339e55d02 100644 --- a/public/docs/_examples/dependency-injection/dart/lib/app_component.dart +++ b/public/docs/_examples/dependency-injection/dart/lib/app_component.dart @@ -22,7 +22,9 @@ import 'providers_component.dart';

- ''', + + + ''', directives: const [ CarComponent, HeroesComponent, diff --git a/public/docs/_examples/dependency-injection/dart/lib/providers_component.dart b/public/docs/_examples/dependency-injection/dart/lib/providers_component.dart index 08c9e542a8..16e248f000 100644 --- a/public/docs/_examples/dependency-injection/dart/lib/providers_component.dart +++ b/public/docs/_examples/dependency-injection/dart/lib/providers_component.dart @@ -224,7 +224,11 @@ class Provider9Component implements OnInit { // Sample providers 1 to 7 illustrate a required logger dependency. // Optional logger, can be null. -@Component(selector: 'provider-10', template: '{{log}}') +@Component( + selector: 'provider-10', + template: '{{log}}', + providers: const [const Provider(Logger, useValue: null)] +) class Provider10Component implements OnInit { final Logger _logger; String log; diff --git a/public/docs/_examples/dependency-injection/dart/pubspec.yaml b/public/docs/_examples/dependency-injection/dart/pubspec.yaml index 14030bc995..297f8bfb80 100644 --- a/public/docs/_examples/dependency-injection/dart/pubspec.yaml +++ b/public/docs/_examples/dependency-injection/dart/pubspec.yaml @@ -6,8 +6,10 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 + test: any transformers: - angular2: platform_directives: @@ -16,5 +18,3 @@ transformers: - 'package:angular2/common.dart#COMMON_PIPES' entry_points: web/main.dart - dart_to_js_script_rewriter -dev_dependencies: - test: any diff --git a/public/docs/_examples/dependency-injection/dart/web/index.html b/public/docs/_examples/dependency-injection/dart/web/index.html index cd3dfdb6cf..8a89dc5d59 100644 --- a/public/docs/_examples/dependency-injection/dart/web/index.html +++ b/public/docs/_examples/dependency-injection/dart/web/index.html @@ -10,6 +10,5 @@ Loading... - Loading my-providers ... diff --git a/public/docs/_examples/dependency-injection/dart/web/main.dart b/public/docs/_examples/dependency-injection/dart/web/main.dart index 5ec8717ed2..06582f0fbb 100644 --- a/public/docs/_examples/dependency-injection/dart/web/main.dart +++ b/public/docs/_examples/dependency-injection/dart/web/main.dart @@ -1,11 +1,9 @@ import 'package:angular2/platform/browser.dart'; import 'package:dependency_injection/app_component.dart'; -import 'package:dependency_injection/providers_component.dart'; void main() { //#docregion bootstrap bootstrap(AppComponent); //#enddocregion bootstrap - bootstrap(ProvidersComponent); } diff --git a/public/docs/_examples/dependency-injection/ts/app/app.component.ts b/public/docs/_examples/dependency-injection/ts/app/app.component.ts index 9a50661a84..94e1f0b988 100644 --- a/public/docs/_examples/dependency-injection/ts/app/app.component.ts +++ b/public/docs/_examples/dependency-injection/ts/app/app.component.ts @@ -22,6 +22,7 @@ import { UserService } from './user.service';

+ `, providers: [Logger] }) diff --git a/public/docs/_examples/dependency-injection/ts/app/app.module.ts b/public/docs/_examples/dependency-injection/ts/app/app.module.ts index 5ef7678573..2929f502a2 100644 --- a/public/docs/_examples/dependency-injection/ts/app/app.module.ts +++ b/public/docs/_examples/dependency-injection/ts/app/app.module.ts @@ -53,7 +53,7 @@ import { { provide: APP_CONFIG, useValue: HERO_DI_CONFIG } ], // #enddocregion ngmodule-providers - bootstrap: [ AppComponent, ProvidersComponent ] + bootstrap: [ AppComponent ] }) export class AppModule { } // #enddocregion ngmodule diff --git a/public/docs/_examples/dependency-injection/ts/app/providers.component.ts b/public/docs/_examples/dependency-injection/ts/app/providers.component.ts index f8c7ee81fd..d74b25d780 100644 --- a/public/docs/_examples/dependency-injection/ts/app/providers.component.ts +++ b/public/docs/_examples/dependency-injection/ts/app/providers.component.ts @@ -229,7 +229,8 @@ let some_message = 'Hello from the injected logger'; @Component({ selector: 'provider-10', - template: template + template: template, + providers: [{ provide: Logger, useValue: null }] }) export class Provider10Component implements OnInit { log: string; diff --git a/public/docs/_examples/dependency-injection/ts/index.html b/public/docs/_examples/dependency-injection/ts/index.html index ce65fac8b7..c3586c230e 100644 --- a/public/docs/_examples/dependency-injection/ts/index.html +++ b/public/docs/_examples/dependency-injection/ts/index.html @@ -7,7 +7,7 @@ - + @@ -22,7 +22,6 @@ Loading my-app ... - Loading my-providers ... diff --git a/public/docs/_examples/displaying-data/dart/pubspec.yaml b/public/docs/_examples/displaying-data/dart/pubspec.yaml index 8fe96ff267..fbd1efd55a 100644 --- a/public/docs/_examples/displaying-data/dart/pubspec.yaml +++ b/public/docs/_examples/displaying-data/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/displaying-data/ts/index.html b/public/docs/_examples/displaying-data/ts/index.html index d9e9291661..e18da1b26e 100644 --- a/public/docs/_examples/displaying-data/ts/index.html +++ b/public/docs/_examples/displaying-data/ts/index.html @@ -6,7 +6,7 @@ - + diff --git a/public/docs/_examples/forms/dart/pubspec.yaml b/public/docs/_examples/forms/dart/pubspec.yaml index 5a456f3c18..470a07559c 100644 --- a/public/docs/_examples/forms/dart/pubspec.yaml +++ b/public/docs/_examples/forms/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/forms/ts/index.html b/public/docs/_examples/forms/ts/index.html index 50f8747546..984ddae1e0 100644 --- a/public/docs/_examples/forms/ts/index.html +++ b/public/docs/_examples/forms/ts/index.html @@ -15,7 +15,7 @@ - + diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml b/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml index da716d37eb..e17503199d 100644 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml +++ b/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero-editor.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero-editor.component.ts index 65f0b7f066..b45960b179 100644 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero-editor.component.ts +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero-editor.component.ts @@ -21,8 +21,8 @@ import { Hero } from './hero'; }) export class HeroEditorComponent { - @Output() canceled = new EventEmitter(); - @Output() saved = new EventEmitter(); + @Output() canceled = new EventEmitter(); + @Output() saved = new EventEmitter(); constructor(private restoreService: RestoreService) {} @@ -36,12 +36,12 @@ export class HeroEditorComponent { } onSaved () { - this.saved.next(this.restoreService.getItem()); + this.saved.emit(this.restoreService.getItem()); } onCanceled () { this.hero = this.restoreService.restoreItem(); - this.canceled.next(this.hero); + this.canceled.emit(this.hero); } } // #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/index.html b/public/docs/_examples/hierarchical-dependency-injection/ts/index.html index 91d2dc8894..c13e9243aa 100644 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/index.html +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/index.html @@ -6,7 +6,7 @@ - + diff --git a/public/docs/_examples/homepage-hello-world/ts/index.1.html b/public/docs/_examples/homepage-hello-world/ts/index.1.html index 7ea19e1842..e84cfb5de7 100644 --- a/public/docs/_examples/homepage-hello-world/ts/index.1.html +++ b/public/docs/_examples/homepage-hello-world/ts/index.1.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/homepage-hello-world/ts/index.html b/public/docs/_examples/homepage-hello-world/ts/index.html index 283343ace7..7d5395fb0f 100644 --- a/public/docs/_examples/homepage-hello-world/ts/index.html +++ b/public/docs/_examples/homepage-hello-world/ts/index.html @@ -7,7 +7,7 @@ - + diff --git a/public/docs/_examples/homepage-tabs/ts/index.1.html b/public/docs/_examples/homepage-tabs/ts/index.1.html index 5ca7d182a6..dbf14c628a 100644 --- a/public/docs/_examples/homepage-tabs/ts/index.1.html +++ b/public/docs/_examples/homepage-tabs/ts/index.1.html @@ -9,7 +9,7 @@ - + diff --git a/public/docs/_examples/homepage-tabs/ts/index.html b/public/docs/_examples/homepage-tabs/ts/index.html index d047702a13..ccc8fcdda3 100644 --- a/public/docs/_examples/homepage-tabs/ts/index.html +++ b/public/docs/_examples/homepage-tabs/ts/index.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/homepage-todo/ts/app/todo_form.ts b/public/docs/_examples/homepage-todo/ts/app/todo_form.ts index cf438a2abf..38e8d991a7 100644 --- a/public/docs/_examples/homepage-todo/ts/app/todo_form.ts +++ b/public/docs/_examples/homepage-todo/ts/app/todo_form.ts @@ -17,7 +17,7 @@ export class TodoFormComponent { addTodo() { if (this.task) { - this.newTask.next({text: this.task, done: false}); + this.newTask.emit({text: this.task, done: false}); } this.task = ''; } diff --git a/public/docs/_examples/homepage-todo/ts/index.1.html b/public/docs/_examples/homepage-todo/ts/index.1.html index 4ac9552d89..ae0eef860b 100644 --- a/public/docs/_examples/homepage-todo/ts/index.1.html +++ b/public/docs/_examples/homepage-todo/ts/index.1.html @@ -9,7 +9,7 @@ - + diff --git a/public/docs/_examples/homepage-todo/ts/index.html b/public/docs/_examples/homepage-todo/ts/index.html index 6bed22fce1..de82c12ddd 100644 --- a/public/docs/_examples/homepage-todo/ts/index.html +++ b/public/docs/_examples/homepage-todo/ts/index.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml b/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml index 11fe5c36db..5e944da574 100644 --- a/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml +++ b/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/lifecycle-hooks/dart/web/index.html b/public/docs/_examples/lifecycle-hooks/dart/web/index.html index e698da98bc..1d778919bc 100644 --- a/public/docs/_examples/lifecycle-hooks/dart/web/index.html +++ b/public/docs/_examples/lifecycle-hooks/dart/web/index.html @@ -3,7 +3,7 @@ - Angular 2 Lifecycle Hooks + Angular Lifecycle Hooks diff --git a/public/docs/_examples/lifecycle-hooks/ts/index.html b/public/docs/_examples/lifecycle-hooks/ts/index.html index 07cf7d4a03..4da8212d42 100644 --- a/public/docs/_examples/lifecycle-hooks/ts/index.html +++ b/public/docs/_examples/lifecycle-hooks/ts/index.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/ngmodule/ts/index.0.html b/public/docs/_examples/ngmodule/ts/index.0.html index 7deb1e2a5f..97f8f9e685 100644 --- a/public/docs/_examples/ngmodule/ts/index.0.html +++ b/public/docs/_examples/ngmodule/ts/index.0.html @@ -7,13 +7,12 @@ - + - - - - - diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index a46ac1b718..160fa06771 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -15,19 +15,20 @@ } ], "dependencies": { - "@angular/common": "~2.1.1", - "@angular/compiler": "~2.1.1", - "@angular/compiler-cli": "~2.1.1", - "@angular/core": "~2.1.1", - "@angular/forms": "~2.1.1", - "@angular/http": "~2.1.1", - "@angular/platform-browser": "~2.1.1", - "@angular/platform-browser-dynamic": "~2.1.1", - "@angular/platform-server": "~2.1.1", - "@angular/router": "~3.1.1", - "@angular/upgrade": "~2.1.1", + "@angular/common": "~2.2.0", + "@angular/compiler": "~2.2.0", + "@angular/compiler-cli": "~2.2.0", + "@angular/core": "~2.2.0", + "@angular/forms": "~2.2.0", + "@angular/http": "~2.2.0", + "@angular/platform-browser": "~2.2.0", + "@angular/platform-browser-dynamic": "~2.2.0", + "@angular/platform-server": "~2.2.0", + "@angular/router": "~3.2.0", + "@angular/upgrade": "~2.2.0", + + "angular-in-memory-web-api": "~0.1.15", - "angular-in-memory-web-api": "~0.1.13", "core-js": "^2.4.1", "reflect-metadata": "^0.1.8", "rollup": "^0.36.0", @@ -51,6 +52,9 @@ "@types/selenium-webdriver": "^2.53.32", "angular2-template-loader": "^0.4.0", "awesome-typescript-loader": "^2.2.4", + "babel-cli": "^6.16.0", + "babel-preset-angular2": "^0.0.2", + "babel-preset-es2015": "^6.16.0", "canonical-path": "0.0.2", "concurrently": "^3.0.0", "css-loader": "^0.25.0", diff --git a/public/docs/_examples/pipes/dart/pubspec.yaml b/public/docs/_examples/pipes/dart/pubspec.yaml index 6a69c51627..59f20da33d 100644 --- a/public/docs/_examples/pipes/dart/pubspec.yaml +++ b/public/docs/_examples/pipes/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/pipes/dart/web/main.dart b/public/docs/_examples/pipes/dart/web/main.dart index 3266c05644..dddf5d144d 100644 --- a/public/docs/_examples/pipes/dart/web/main.dart +++ b/public/docs/_examples/pipes/dart/web/main.dart @@ -1,9 +1,7 @@ import 'package:angular2/platform/browser.dart'; import 'package:pipe_examples/app_component.dart'; -import 'package:pipe_examples/hero_birthday1_component.dart'; -main() { +void main() { bootstrap(AppComponent); - bootstrap(HeroBirthdayComponent); } diff --git a/public/docs/_examples/pipes/ts/index.html b/public/docs/_examples/pipes/ts/index.html index 0b1a46f328..57b188648d 100644 --- a/public/docs/_examples/pipes/ts/index.html +++ b/public/docs/_examples/pipes/ts/index.html @@ -6,7 +6,7 @@ - + diff --git a/public/docs/_examples/protractor-helpers.ts b/public/docs/_examples/protractor-helpers.ts index f3f784e613..61af74ba30 100644 --- a/public/docs/_examples/protractor-helpers.ts +++ b/public/docs/_examples/protractor-helpers.ts @@ -1,3 +1,5 @@ +import { browser } from 'protractor'; + export var appLang = { appIsTs: false, appIsJs: false, @@ -21,16 +23,13 @@ export function itIf(cond: boolean, name: string, func: (done: DoneFn) => void): } } - // TODO Jesus - figure out what's needed here for the new upgrade chapters -// Allow changing bootstrap mode to NG1 for upgrade tests +// protractor.config.js is set to ng2 mode by default, so we must manually +// change it for upgradeAdapter tests export function setProtractorToNg1Mode(): void { - // browser.rootEl = 'body'; - - // let disableNgAnimate = function() { - // angular.module('disableNgAnimate', []).run(['$animate', function($animate: any) { - // $animate.enabled(false); - // }]); - // }; - - // browser.addMockModule('disableNgAnimate', disableNgAnimate); + browser.rootEl = 'body'; +} + +export function setProtractorToHybridMode() { + setProtractorToNg1Mode(); + browser.ng12Hybrid = true; } diff --git a/public/docs/_examples/quickstart/dart/lib/app_component.dart b/public/docs/_examples/quickstart/dart/lib/app_component.dart index b300a28992..c8d3e6f143 100644 --- a/public/docs/_examples/quickstart/dart/lib/app_component.dart +++ b/public/docs/_examples/quickstart/dart/lib/app_component.dart @@ -5,7 +5,7 @@ import 'package:angular2/core.dart'; // #docregion metadata @Component( selector: 'my-app', - template: '

My First Angular App

') + template: '

Hello Angular!

') // #enddocregion metadata // #docregion class class AppComponent {} diff --git a/public/docs/_examples/quickstart/dart/pubspec.yaml b/public/docs/_examples/quickstart/dart/pubspec.yaml index d497066817..a8165a0e28 100644 --- a/public/docs/_examples/quickstart/dart/pubspec.yaml +++ b/public/docs/_examples/quickstart/dart/pubspec.yaml @@ -1,5 +1,5 @@ # #docregion -name: angular2_quickstart +name: angular_quickstart description: QuickStart version: 0.0.1 environment: diff --git a/public/docs/_examples/quickstart/dart/web/main.dart b/public/docs/_examples/quickstart/dart/web/main.dart index b542eebb9f..4b32095825 100644 --- a/public/docs/_examples/quickstart/dart/web/main.dart +++ b/public/docs/_examples/quickstart/dart/web/main.dart @@ -1,7 +1,7 @@ // #docregion import 'package:angular2/platform/browser.dart'; -import 'package:angular2_quickstart/app_component.dart'; +import 'package:angular_quickstart/app_component.dart'; void main() { bootstrap(AppComponent); diff --git a/public/docs/_examples/quickstart/e2e-spec.ts b/public/docs/_examples/quickstart/e2e-spec.ts index a548ec833a..0acc433926 100644 --- a/public/docs/_examples/quickstart/e2e-spec.ts +++ b/public/docs/_examples/quickstart/e2e-spec.ts @@ -1,10 +1,10 @@ -'use strict'; // necessary for es6 output in node +'use strict'; // necessary for es6 output in node import { browser, element, by } from 'protractor'; describe('QuickStart E2E Tests', function () { - let expectedMsg = 'My First Angular App'; + let expectedMsg = 'Hello Angular!'; beforeEach(function () { browser.get(''); diff --git a/public/docs/_examples/quickstart/js/app/app.component.js b/public/docs/_examples/quickstart/js/app/app.component.js index 69d3e9127e..c770e8d1fb 100644 --- a/public/docs/_examples/quickstart/js/app/app.component.js +++ b/public/docs/_examples/quickstart/js/app/app.component.js @@ -10,7 +10,7 @@ ng.core.Component({ // #enddocregion ng-namespace-funcs selector: 'my-app', - template: '

My First Angular App

' + template: '

Hello Angular!

' // #docregion ng-namespace-funcs }) // #enddocregion component diff --git a/public/docs/_examples/quickstart/js/package.1.json b/public/docs/_examples/quickstart/js/package.1.json index 212ffc8735..497c673b7f 100644 --- a/public/docs/_examples/quickstart/js/package.1.json +++ b/public/docs/_examples/quickstart/js/package.1.json @@ -12,17 +12,17 @@ } ], "dependencies": { - "@angular/common": "~2.1.1", - "@angular/compiler": "~2.1.1", - "@angular/core": "~2.1.1", - "@angular/forms": "~2.1.1", - "@angular/http": "~2.1.1", - "@angular/platform-browser": "~2.1.1", - "@angular/platform-browser-dynamic": "~2.1.1", - "@angular/router": "~3.1.1", - "@angular/upgrade": "~2.1.1", + "@angular/common": "~2.2.0", + "@angular/compiler": "~2.2.0", + "@angular/core": "~2.2.0", + "@angular/forms": "~2.2.0", + "@angular/http": "~2.2.0", + "@angular/platform-browser": "~2.2.0", + "@angular/platform-browser-dynamic": "~2.2.0", + "@angular/router": "~3.2.0", + "@angular/upgrade": "~2.2.0", - "angular-in-memory-web-api": "~0.1.5", + "angular-in-memory-web-api": "~0.1.15", "core-js": "^2.4.1", "reflect-metadata": "^0.1.8", "rxjs": "5.0.0-beta.12", diff --git a/public/docs/_examples/quickstart/ts/app/app.component.ts b/public/docs/_examples/quickstart/ts/app/app.component.ts index e6c635440b..b80c22caa5 100644 --- a/public/docs/_examples/quickstart/ts/app/app.component.ts +++ b/public/docs/_examples/quickstart/ts/app/app.component.ts @@ -6,7 +6,7 @@ import { Component } from '@angular/core'; // #docregion metadata @Component({ selector: 'my-app', - template: '

My First Angular App

' + template: '

Hello Angular!

' }) // #enddocregion metadata // #docregion class diff --git a/public/docs/_examples/quickstart/ts/index.html b/public/docs/_examples/quickstart/ts/index.html index 4ee082433c..b7d82ca7c8 100644 --- a/public/docs/_examples/quickstart/ts/index.html +++ b/public/docs/_examples/quickstart/ts/index.html @@ -10,7 +10,7 @@ - + diff --git a/public/docs/_examples/quickstart/ts/package.1.json b/public/docs/_examples/quickstart/ts/package.1.json index 0eddc20502..3236914309 100644 --- a/public/docs/_examples/quickstart/ts/package.1.json +++ b/public/docs/_examples/quickstart/ts/package.1.json @@ -14,17 +14,17 @@ } ], "dependencies": { - "@angular/common": "~2.1.1", - "@angular/compiler": "~2.1.1", - "@angular/core": "~2.1.1", - "@angular/forms": "~2.1.1", - "@angular/http": "~2.1.1", - "@angular/platform-browser": "~2.1.1", - "@angular/platform-browser-dynamic": "~2.1.1", - "@angular/router": "~3.1.1", - "@angular/upgrade": "~2.1.1", + "@angular/common": "~2.2.0", + "@angular/compiler": "~2.2.0", + "@angular/core": "~2.2.0", + "@angular/forms": "~2.2.0", + "@angular/http": "~2.2.0", + "@angular/platform-browser": "~2.2.0", + "@angular/platform-browser-dynamic": "~2.2.0", + "@angular/router": "~3.2.0", + "@angular/upgrade": "~2.2.0", - "angular-in-memory-web-api": "~0.1.13", + "angular-in-memory-web-api": "~0.1.15", "core-js": "^2.4.1", "reflect-metadata": "^0.1.8", "rxjs": "5.0.0-beta.12", diff --git a/public/docs/_examples/quickstart/ts/systemjs.config.1.js b/public/docs/_examples/quickstart/ts/systemjs.config.1.js index 2b39cec3f7..f2bf28858b 100644 --- a/public/docs/_examples/quickstart/ts/systemjs.config.1.js +++ b/public/docs/_examples/quickstart/ts/systemjs.config.1.js @@ -22,8 +22,10 @@ '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'npm:@angular/http/bundles/http.umd.js', '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', // other libraries 'rxjs': 'npm:rxjs', diff --git a/public/docs/_examples/router/ts/app/admin/admin-routing.module.1.ts b/public/docs/_examples/router/ts/app/admin/admin-routing.module.1.ts index 0cb1d8f5c7..e7d83f113f 100644 --- a/public/docs/_examples/router/ts/app/admin/admin-routing.module.1.ts +++ b/public/docs/_examples/router/ts/app/admin/admin-routing.module.1.ts @@ -1,7 +1,7 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { AdminComponent } from './admin.component'; import { AdminDashboardComponent } from './admin-dashboard.component'; @@ -9,24 +9,26 @@ import { ManageCrisesComponent } from './manage-crises.component'; import { ManageHeroesComponent } from './manage-heroes.component'; // #docregion admin-routes -@NgModule({ - imports: [ - RouterModule.forChild([ +const adminRoutes: Routes = [ + { + path: 'admin', + component: AdminComponent, + children: [ { - path: 'admin', - component: AdminComponent, + path: '', children: [ - { - path: '', - children: [ - { path: 'crises', component: ManageCrisesComponent }, - { path: 'heroes', component: ManageHeroesComponent }, - { path: '', component: AdminDashboardComponent } - ] - } + { path: 'crises', component: ManageCrisesComponent }, + { path: 'heroes', component: ManageHeroesComponent }, + { path: '', component: AdminDashboardComponent } ] } - ]) + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(adminRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/admin/admin-routing.module.2.ts b/public/docs/_examples/router/ts/app/admin/admin-routing.module.2.ts index 2087d7c913..dc3f28b5c4 100644 --- a/public/docs/_examples/router/ts/app/admin/admin-routing.module.2.ts +++ b/public/docs/_examples/router/ts/app/admin/admin-routing.module.2.ts @@ -1,7 +1,7 @@ // #docplaster // #docregion import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { RouterModule, Routes } from '@angular/router'; import { AdminComponent } from './admin.component'; import { AdminDashboardComponent } from './admin-dashboard.component'; @@ -11,29 +11,31 @@ import { ManageHeroesComponent } from './manage-heroes.component'; // #docregion admin-route, can-activate-child import { AuthGuard } from '../auth-guard.service'; +const adminRoutes: Routes = [ + { + path: 'admin', + component: AdminComponent, + canActivate: [AuthGuard], + children: [ + { + path: '', + children: [ + { path: 'crises', component: ManageCrisesComponent }, + { path: 'heroes', component: ManageHeroesComponent }, + { path: '', component: AdminDashboardComponent } + ], + // #enddocregion admin-route + // #docregion can-activate-child + canActivateChild: [AuthGuard] + // #docregion admin-route + } + ] + } +]; + @NgModule({ imports: [ - RouterModule.forChild([ - { - path: 'admin', - component: AdminComponent, - canActivate: [AuthGuard], - children: [ - { - path: '', - children: [ - { path: 'crises', component: ManageCrisesComponent }, - { path: 'heroes', component: ManageHeroesComponent }, - { path: '', component: AdminDashboardComponent } - ], - // #enddocregion admin-route - // #docregion can-activate-child - canActivateChild: [AuthGuard] - // #docregion admin-route - } - ] - } - ]) + RouterModule.forChild(adminRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/admin/admin-routing.module.3.ts b/public/docs/_examples/router/ts/app/admin/admin-routing.module.3.ts index 92878febb2..63f1c9aaf4 100644 --- a/public/docs/_examples/router/ts/app/admin/admin-routing.module.3.ts +++ b/public/docs/_examples/router/ts/app/admin/admin-routing.module.3.ts @@ -1,7 +1,7 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { AdminComponent } from './admin.component'; import { AdminDashboardComponent } from './admin-dashboard.component'; @@ -12,26 +12,28 @@ import { ManageHeroesComponent } from './manage-heroes.component'; import { AuthGuard } from '../auth-guard.service'; // #docregion can-activate-child -@NgModule({ - imports: [ - RouterModule.forChild([ +const adminRoutes: Routes = [ + { + path: 'admin', + component: AdminComponent, + canActivate: [AuthGuard], + children: [ { - path: 'admin', - component: AdminComponent, - canActivate: [AuthGuard], + path: '', + canActivateChild: [AuthGuard], children: [ - { - path: '', - canActivateChild: [AuthGuard], - children: [ - { path: 'crises', component: ManageCrisesComponent }, - { path: 'heroes', component: ManageHeroesComponent }, - { path: '', component: AdminDashboardComponent } - ] - } + { path: 'crises', component: ManageCrisesComponent }, + { path: 'heroes', component: ManageHeroesComponent }, + { path: '', component: AdminDashboardComponent } ] } - ]) + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(adminRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/admin/admin-routing.module.ts b/public/docs/_examples/router/ts/app/admin/admin-routing.module.ts index b83a75945b..a6ab988005 100644 --- a/public/docs/_examples/router/ts/app/admin/admin-routing.module.ts +++ b/public/docs/_examples/router/ts/app/admin/admin-routing.module.ts @@ -1,7 +1,7 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { AdminComponent } from './admin.component'; import { AdminDashboardComponent } from './admin-dashboard.component'; @@ -11,26 +11,28 @@ import { ManageHeroesComponent } from './manage-heroes.component'; // #docregion admin-route import { AuthGuard } from '../auth-guard.service'; -@NgModule({ - imports: [ - RouterModule.forChild([ +const adminRoutes: Routes = [ + { + path: '', + component: AdminComponent, + canActivate: [AuthGuard], + children: [ { path: '', - component: AdminComponent, - canActivate: [AuthGuard], + canActivateChild: [AuthGuard], children: [ - { - path: '', - canActivateChild: [AuthGuard], - children: [ - { path: 'crises', component: ManageCrisesComponent }, - { path: 'heroes', component: ManageHeroesComponent }, - { path: '', component: AdminDashboardComponent } - ] - } + { path: 'crises', component: ManageCrisesComponent }, + { path: 'heroes', component: ManageHeroesComponent }, + { path: '', component: AdminDashboardComponent } ] } - ]) + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(adminRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/app-routing.module.1.ts b/public/docs/_examples/router/ts/app/app-routing.module.1.ts index 8be1df9926..8b5f6983f5 100644 --- a/public/docs/_examples/router/ts/app/app-routing.module.1.ts +++ b/public/docs/_examples/router/ts/app/app-routing.module.1.ts @@ -1,17 +1,19 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { CrisisListComponent } from './crisis-list.component'; import { HeroListComponent } from './hero-list.component'; +const appRoutes: Routes = [ + { path: 'crisis-center', component: CrisisListComponent }, + { path: 'heroes', component: HeroListComponent } +]; + @NgModule({ imports: [ - RouterModule.forRoot([ - { path: 'crisis-center', component: CrisisListComponent }, - { path: 'heroes', component: HeroListComponent } - ]) + RouterModule.forRoot(appRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/app-routing.module.2.ts b/public/docs/_examples/router/ts/app/app-routing.module.2.ts index eed5688574..53f0f24056 100644 --- a/public/docs/_examples/router/ts/app/app-routing.module.2.ts +++ b/public/docs/_examples/router/ts/app/app-routing.module.2.ts @@ -1,15 +1,17 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { CrisisListComponent } from './crisis-list.component'; +const appRoutes: Routes = [ + { path: 'crisis-center', component: CrisisListComponent } +]; + @NgModule({ imports: [ - RouterModule.forRoot([ - { path: 'crisis-center', component: CrisisListComponent }, - ]) + RouterModule.forRoot(appRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/app-routing.module.3.ts b/public/docs/_examples/router/ts/app/app-routing.module.3.ts index a30d061dc3..5e8a08e40a 100644 --- a/public/docs/_examples/router/ts/app/app-routing.module.3.ts +++ b/public/docs/_examples/router/ts/app/app-routing.module.3.ts @@ -1,13 +1,15 @@ // #docplaster // #docregion import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { RouterModule, Routes } from '@angular/router'; + +const appRoutes: Routes = [ + +]; @NgModule({ imports: [ - RouterModule.forRoot([ - - ]) + RouterModule.forRoot(appRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/app-routing.module.4.ts b/public/docs/_examples/router/ts/app/app-routing.module.4.ts index 2ce11b8105..7ea7cb11ed 100644 --- a/public/docs/_examples/router/ts/app/app-routing.module.4.ts +++ b/public/docs/_examples/router/ts/app/app-routing.module.4.ts @@ -1,15 +1,17 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { CanDeactivateGuard } from './can-deactivate-guard.service'; +const appRoutes: Routes = [ + +]; + @NgModule({ imports: [ - RouterModule.forRoot([ - - ]) + RouterModule.forRoot(appRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/app-routing.module.5.ts b/public/docs/_examples/router/ts/app/app-routing.module.5.ts index 6e35f64f73..33505b532b 100644 --- a/public/docs/_examples/router/ts/app/app-routing.module.5.ts +++ b/public/docs/_examples/router/ts/app/app-routing.module.5.ts @@ -2,7 +2,7 @@ // #docregion import { NgModule } from '@angular/core'; // #docregion import-router -import { RouterModule } from '@angular/router'; +import { RouterModule, Routes } from '@angular/router'; // #enddocregion import-router import { CanDeactivateGuard } from './can-deactivate-guard.service'; @@ -11,17 +11,20 @@ import { AuthGuard } from './auth-guard.service'; // #enddocregion can-load-guard // #docregion lazy-load-admin, can-load-guard + +const appRoutes: Routes = [ + { + path: 'admin', + loadChildren: 'app/admin/admin.module#AdminModule', +// #enddocregion lazy-load-admin + canLoad: [AuthGuard] +// #docregion lazy-load-admin + } +]; + @NgModule({ imports: [ - RouterModule.forRoot([ - { - path: 'admin', - loadChildren: 'app/admin/admin.module#AdminModule', - // #enddocregion lazy-load-admin - canLoad: [AuthGuard] - // #docregion lazy-load-admin - } - ]) + RouterModule.forRoot(appRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/app-routing.module.6.ts b/public/docs/_examples/router/ts/app/app-routing.module.6.ts index 68bcc30413..c9f1f2916c 100644 --- a/public/docs/_examples/router/ts/app/app-routing.module.6.ts +++ b/public/docs/_examples/router/ts/app/app-routing.module.6.ts @@ -2,7 +2,7 @@ // #docregion, preload-v1 import { NgModule } from '@angular/core'; import { - RouterModule, + RouterModule, Routes, // #enddocregion preload-v1 PreloadAllModules // #docregion preload-v1 @@ -11,27 +11,30 @@ import { import { CanDeactivateGuard } from './can-deactivate-guard.service'; import { AuthGuard } from './auth-guard.service'; +const appRoutes: Routes = [ + { + path: 'admin', + loadChildren: 'app/admin/admin.module#AdminModule', + canLoad: [AuthGuard] + }, + { + path: '', + redirectTo: '/heroes', + pathMatch: 'full' + }, + { + path: 'crisis-center', + loadChildren: 'app/crisis-center/crisis-center.module#CrisisCenterModule' + } +]; + @NgModule({ imports: [ - RouterModule.forRoot([ - { - path: 'admin', - loadChildren: 'app/admin/admin.module#AdminModule', - canLoad: [AuthGuard] - }, - { - path: '', - redirectTo: '/heroes', - pathMatch: 'full' - }, - { - path: 'crisis-center', - loadChildren: 'app/crisis-center/crisis-center.module#CrisisCenterModule' - }, - ], - // #enddocregion preload-v1 - { preloadingStrategy: PreloadAllModules } - // #docregion preload-v1 + RouterModule.forRoot( + appRoutes + // #enddocregion preload-v1 + , { preloadingStrategy: PreloadAllModules } + // #docregion preload-v1 ) ], exports: [ diff --git a/public/docs/_examples/router/ts/app/app-routing.module.ts b/public/docs/_examples/router/ts/app/app-routing.module.ts index 8fa63edb1c..9cef4db94e 100644 --- a/public/docs/_examples/router/ts/app/app-routing.module.ts +++ b/public/docs/_examples/router/ts/app/app-routing.module.ts @@ -1,36 +1,40 @@ // #docplaster // #docregion, preload-v1 -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { CanDeactivateGuard } from './can-deactivate-guard.service'; import { AuthGuard } from './auth-guard.service'; import { PreloadSelectedModules } from './selective-preload-strategy'; +const appRoutes: Routes = [ + { + path: 'admin', + loadChildren: 'app/admin/admin.module#AdminModule', + canLoad: [AuthGuard] + }, + { + path: '', + redirectTo: '/heroes', + pathMatch: 'full' + }, + // #docregion preload-v2 + { + path: 'crisis-center', + loadChildren: 'app/crisis-center/crisis-center.module#CrisisCenterModule', + data: { + preload: true + } + } + // #enddocregion preload-v2 +]; + @NgModule({ imports: [ - RouterModule.forRoot([ - { - path: 'admin', - loadChildren: 'app/admin/admin.module#AdminModule', - canLoad: [AuthGuard] - }, - { - path: '', - redirectTo: '/heroes', - pathMatch: 'full' - }, - // #docregion preload-v2 - { - path: 'crisis-center', - loadChildren: 'app/crisis-center/crisis-center.module#CrisisCenterModule', - data: { - preload: true - } - } - // #enddocregion preload-v2 - ], - { preloadingStrategy: PreloadSelectedModules }) + RouterModule.forRoot( + appRoutes, + { preloadingStrategy: PreloadSelectedModules } + ) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/app.module.0.ts b/public/docs/_examples/router/ts/app/app.module.0.ts index df91982cd1..9844f30586 100644 --- a/public/docs/_examples/router/ts/app/app.module.0.ts +++ b/public/docs/_examples/router/ts/app/app.module.0.ts @@ -1,10 +1,10 @@ // #docplaster // #docregion // #docregion router-basics -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; import { AppComponent } from './app.component'; import { HeroListComponent } from './hero-list.component'; @@ -14,27 +14,29 @@ import { PageNotFoundComponent as HeroDetailComponent } from './not-found.compon import { PageNotFoundComponent as HomeComponent } from './not-found.component'; // #docregion route-config +const appRoutes: Routes = [ + // #docregion route-defs + // #docregion hero-detail-route + { path: 'hero/:id', component: HeroDetailComponent }, + // #enddocregion hero-detail-route + { path: 'crisis-center', component: CrisisListComponent }, + { + path: 'heroes', + component: HeroListComponent, + data: { + title: 'Heroes List' + } + }, + { path: '', component: HomeComponent }, + // #enddocregion route-defs + { path: '**', component: PageNotFoundComponent } +]; + @NgModule({ imports: [ BrowserModule, FormsModule, - RouterModule.forRoot([ - // #docregion route-defs - // #docregion hero-detail-route - { path: 'hero/:id', component: HeroDetailComponent }, - // #enddocregion hero-detail-route - { path: 'crisis-center', component: CrisisListComponent }, - { - path: 'heroes', - component: HeroListComponent, - data: { - title: 'Heroes List' - } - }, - { path: '', component: HomeComponent }, - // #enddocregion route-defs - { path: '**', component: PageNotFoundComponent } - ]) + RouterModule.forRoot(appRoutes) ], declarations: [ AppComponent, diff --git a/public/docs/_examples/router/ts/app/app.module.1.ts b/public/docs/_examples/router/ts/app/app.module.1.ts index 6338c9bca3..f98ef7528e 100644 --- a/public/docs/_examples/router/ts/app/app.module.1.ts +++ b/public/docs/_examples/router/ts/app/app.module.1.ts @@ -1,10 +1,10 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; // #docregion import-router, route-config -import { RouterModule } from '@angular/router'; +import { RouterModule, Routes } from '@angular/router'; // #enddocregion import-router, route-config // #docregion router-basics @@ -12,16 +12,18 @@ import { AppComponent } from './app.component'; import { CrisisListComponent } from './crisis-list.component'; import { HeroListComponent } from './hero-list.component'; +// #docregion route-config +const appRoutes: Routes = [ + { path: 'crisis-center', component: CrisisListComponent }, + { path: 'heroes', component: HeroListComponent } +]; +// #enddocregion route-config + @NgModule({ imports: [ BrowserModule, FormsModule, - // #docregion route-config - RouterModule.forRoot([ - { path: 'crisis-center', component: CrisisListComponent }, - { path: 'heroes', component: HeroListComponent } - ]) - // #enddocregion route-config + RouterModule.forRoot(appRoutes) ], declarations: [ AppComponent, diff --git a/public/docs/_examples/router/ts/app/app.routing.1.ts b/public/docs/_examples/router/ts/app/app.routing.1.ts deleted file mode 100644 index 736f49b4fb..0000000000 --- a/public/docs/_examples/router/ts/app/app.routing.1.ts +++ /dev/null @@ -1,44 +0,0 @@ -// #docplaster -// #docregion -// #docregion route-config -import { ModuleWithProviders } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; - -// #enddocregion route-config -// #enddocregion - -// #docregion base-routes -import { HeroListComponent } from './hero-list.component'; -import { CrisisCenterComponent } from './crisis-center/crisis-center.component'; -import { HeroDetailComponent } from './heroes/hero-detail.component'; -import { PageNotFoundComponent } from './not-found.component'; -import { PageNotFoundComponent as HomeComponent } from './not-found.component'; -// #enddocregion base-routes - -// #docregion -// #docregion route-config -const appRoutes: Routes = [ - // #docregion route-defs - // #docregion hero-detail-route - { path: 'hero/:id', component: HeroDetailComponent }, - // #enddocregion hero-detail-route - { path: 'crisis-center', component: CrisisCenterComponent }, - { - path: 'heroes', - component: HeroListComponent, - data: { - title: 'Heroes List' - } - }, - { path: '', component: HomeComponent }, - // #enddocregion route-defs - { path: '**', component: PageNotFoundComponent } -]; - -export const appRoutingProviders: any[] = [ - -]; - -export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes); -// #enddocregion route-config -// #enddocregion diff --git a/public/docs/_examples/router/ts/app/app.routing.2.ts b/public/docs/_examples/router/ts/app/app.routing.2.ts deleted file mode 100644 index 1115c9084e..0000000000 --- a/public/docs/_examples/router/ts/app/app.routing.2.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docplaster -// #docregion -import { ModuleWithProviders } from '@angular/core'; -// #docregion route-config -import { Routes, RouterModule } from '@angular/router'; - -// #enddocregion route-config -import { CrisisListComponent } from './crisis-list.component'; -import { HeroListComponent } from './hero-list.component'; - -// #docregion route-config -const appRoutes: Routes = [ - { path: 'crisis-center', component: CrisisListComponent }, - { path: 'heroes', component: HeroListComponent } -]; - -export const appRoutingProviders: any[] = [ - -]; - -export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes); -// #enddocregion route-config diff --git a/public/docs/_examples/router/ts/app/app.routing.3.ts b/public/docs/_examples/router/ts/app/app.routing.3.ts deleted file mode 100644 index 247ec7f2dd..0000000000 --- a/public/docs/_examples/router/ts/app/app.routing.3.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docplaster -// #docregion -import { ModuleWithProviders } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; - -import { CrisisCenterComponent } from './crisis-center/crisis-center.component'; - -const appRoutes: Routes = [ - { path: 'crisis-center', component: CrisisCenterComponent } -]; - -export const appRoutingProviders: any[] = [ - -]; - -export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes); diff --git a/public/docs/_examples/router/ts/app/app.routing.4.ts b/public/docs/_examples/router/ts/app/app.routing.4.ts deleted file mode 100644 index ff04dd8bfd..0000000000 --- a/public/docs/_examples/router/ts/app/app.routing.4.ts +++ /dev/null @@ -1,13 +0,0 @@ -// #docregion -import { ModuleWithProviders } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; - -const appRoutes: Routes = [ - -]; - -export const appRoutingProviders: any[] = [ - -]; - -export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes); diff --git a/public/docs/_examples/router/ts/app/app.routing.5.ts b/public/docs/_examples/router/ts/app/app.routing.5.ts deleted file mode 100644 index 8ce3e0a10f..0000000000 --- a/public/docs/_examples/router/ts/app/app.routing.5.ts +++ /dev/null @@ -1,16 +0,0 @@ -// // #docregion -// import { ModuleWithProviders } from '@angular/core'; -// import { Routes, RouterModule } from '@angular/router'; -// -// import { loginRoutes, -// authProviders } from './login.routing'; -// -// const appRoutes: Routes = [ -// ...loginRoutes -// ]; -// -// export const appRoutingProviders: any[] = [ -// authProviders -// ]; -// -// export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes); diff --git a/public/docs/_examples/router/ts/app/app.routing.6.ts b/public/docs/_examples/router/ts/app/app.routing.6.ts deleted file mode 100644 index 23e2897cf1..0000000000 --- a/public/docs/_examples/router/ts/app/app.routing.6.ts +++ /dev/null @@ -1,21 +0,0 @@ -// // #docregion -// import { ModuleWithProviders } from '@angular/core'; -// // #docregion import-router -// import { Routes, RouterModule } from '@angular/router'; -// // #enddocregion import-router -// -// import { loginRoutes, -// authProviders } from './login.routing'; -// -// import { CanDeactivateGuard } from './can-deactivate-guard.service'; -// -// const appRoutes: Routes = [ -// ...loginRoutes -// ]; -// -// export const appRoutingProviders: any[] = [ -// authProviders, -// CanDeactivateGuard -// ]; -// -// export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes); diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.1.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.1.ts index 829175cea6..e646f467d1 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.1.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.1.ts @@ -1,7 +1,7 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { CrisisCenterHomeComponent } from './crisis-center-home.component'; import { CrisisListComponent } from './crisis-list.component'; @@ -9,30 +9,32 @@ import { CrisisCenterComponent } from './crisis-center.component'; import { CrisisDetailComponent } from './crisis-detail.component'; // #docregion routes -@NgModule({ - imports: [ - RouterModule.forChild([ +const crisisCenterRoutes: Routes = [ + { + path: 'crisis-center', + component: CrisisCenterComponent, + children: [ { - path: 'crisis-center', - component: CrisisCenterComponent, + path: '', + component: CrisisListComponent, children: [ + { + path: ':id', + component: CrisisDetailComponent + }, { path: '', - component: CrisisListComponent, - children: [ - { - path: ':id', - component: CrisisDetailComponent - }, - { - path: '', - component: CrisisCenterHomeComponent - } - ] + component: CrisisCenterHomeComponent } ] } - ]) + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(crisisCenterRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.2.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.2.ts index 9c782edc0e..c3e3561dee 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.2.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.2.ts @@ -1,7 +1,7 @@ // #docplaster // #docregion routes -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { CrisisCenterHomeComponent } from './crisis-center-home.component'; import { CrisisListComponent } from './crisis-list.component'; @@ -18,50 +18,52 @@ import { CrisisDetailResolve } from './crisis-detail-resolve.service'; // #enddocregion crisis-detail-resolve // #docregion routes -@NgModule({ - imports: [ - RouterModule.forChild([ - // #enddocregion routes - // #docregion redirect, routes +const crisisCenterRoutes: Routes = [ +// #enddocregion routes + // #docregion redirect, routes + { + path: '', + redirectTo: '/crisis-center', + pathMatch: 'full' + }, + // #enddocregion redirect, routes + // #docregion routes + { + path: 'crisis-center', + component: CrisisCenterComponent, + children: [ { path: '', - redirectTo: '/crisis-center', - pathMatch: 'full' - }, - // #enddocregion redirect, routes - // #docregion routes - { - path: 'crisis-center', - component: CrisisCenterComponent, + component: CrisisListComponent, children: [ + { + path: ':id', + component: CrisisDetailComponent, + // #enddocregion routes + // #docregion can-deactivate-guard + canDeactivate: [CanDeactivateGuard], + // #enddocregion can-deactivate-guard + // #docregion crisis-detail-resolve + resolve: { + crisis: CrisisDetailResolve + } + // #enddocregion crisis-detail-resolve + // #docregion routes + }, { path: '', - component: CrisisListComponent, - children: [ - { - path: ':id', - component: CrisisDetailComponent, - // #enddocregion routes - // #docregion can-deactivate-guard - canDeactivate: [CanDeactivateGuard], - // #enddocregion can-deactivate-guard - // #docregion crisis-detail-resolve - resolve: { - crisis: CrisisDetailResolve - } - // #enddocregion crisis-detail-resolve - // #docregion routes - }, - { - path: '', - component: CrisisCenterHomeComponent - } - ] + component: CrisisCenterHomeComponent } ] } - // #docregion routes - ]) + ] + } + // #docregion routes +]; + +@NgModule({ + imports: [ + RouterModule.forChild(crisisCenterRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.3.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.3.ts index 693a72f8c2..6d605dbe84 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.3.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.3.ts @@ -1,7 +1,7 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { CrisisCenterHomeComponent } from './crisis-center-home.component'; import { CrisisListComponent } from './crisis-list.component'; @@ -11,36 +11,38 @@ import { CrisisDetailComponent } from './crisis-detail.component'; // #docregion can-deactivate-guard import { CanDeactivateGuard } from '../can-deactivate-guard.service'; -@NgModule({ - imports: [ - RouterModule.forChild([ +const crisisCenterRoutes: Routes = [ + { + path: '', + redirectTo: '/crisis-center', + pathMatch: 'full' + }, + { + path: 'crisis-center', + component: CrisisCenterComponent, + children: [ { path: '', - redirectTo: '/crisis-center', - pathMatch: 'full' - }, - { - path: 'crisis-center', - component: CrisisCenterComponent, + component: CrisisListComponent, children: [ + { + path: ':id', + component: CrisisDetailComponent, + canDeactivate: [CanDeactivateGuard] + }, { path: '', - component: CrisisListComponent, - children: [ - { - path: ':id', - component: CrisisDetailComponent, - canDeactivate: [CanDeactivateGuard] - }, - { - path: '', - component: CrisisCenterHomeComponent - } - ] + component: CrisisCenterHomeComponent } ] } - ]) + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(crisisCenterRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.4.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.4.ts index 17843ace3e..15b346d01f 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.4.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.4.ts @@ -1,7 +1,7 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { CrisisCenterHomeComponent } from './crisis-center-home.component'; import { CrisisListComponent } from './crisis-list.component'; @@ -13,41 +13,43 @@ import { CanDeactivateGuard } from '../can-deactivate-guard.service'; // #docregion crisis-detail-resolve import { CrisisDetailResolve } from './crisis-detail-resolve.service'; -@NgModule({ - imports: [ - RouterModule.forChild([ - // #docregion redirect +const crisisCenterRoutes: Routes = [ + // #docregion redirect + { + path: '', + redirectTo: '/crisis-center', + pathMatch: 'full' + }, + // #enddocregion redirect + { + path: 'crisis-center', + component: CrisisCenterComponent, + children: [ { path: '', - redirectTo: '/crisis-center', - pathMatch: 'full' - }, - // #enddocregion redirect - { - path: 'crisis-center', - component: CrisisCenterComponent, + component: CrisisListComponent, children: [ + { + path: ':id', + component: CrisisDetailComponent, + canDeactivate: [CanDeactivateGuard], + resolve: { + crisis: CrisisDetailResolve + } + }, { path: '', - component: CrisisListComponent, - children: [ - { - path: ':id', - component: CrisisDetailComponent, - canDeactivate: [CanDeactivateGuard], - resolve: { - crisis: CrisisDetailResolve - } - }, - { - path: '', - component: CrisisCenterHomeComponent - } - ] + component: CrisisCenterHomeComponent } ] } - ]) + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(crisisCenterRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.ts index e1d2ae1207..75ca2a7ee8 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center-routing.module.ts @@ -1,7 +1,7 @@ // #docplaster // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { CrisisCenterHomeComponent } from './crisis-center-home.component'; import { CrisisListComponent } from './crisis-list.component'; @@ -13,34 +13,36 @@ import { CanDeactivateGuard } from '../can-deactivate-guard.service'; // #docregion crisis-detail-resolve import { CrisisDetailResolve } from './crisis-detail-resolve.service'; -@NgModule({ - imports: [ - RouterModule.forChild([ +const crisisCenterRoutes: Routes = [ + { + path: '', + component: CrisisCenterComponent, + children: [ { path: '', - component: CrisisCenterComponent, + component: CrisisListComponent, children: [ + { + path: ':id', + component: CrisisDetailComponent, + canDeactivate: [CanDeactivateGuard], + resolve: { + crisis: CrisisDetailResolve + } + }, { path: '', - component: CrisisListComponent, - children: [ - { - path: ':id', - component: CrisisDetailComponent, - canDeactivate: [CanDeactivateGuard], - resolve: { - crisis: CrisisDetailResolve - } - }, - { - path: '', - component: CrisisCenterHomeComponent - } - ] + component: CrisisCenterHomeComponent } ] } - ]) + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(crisisCenterRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-detail-resolve.service.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-detail-resolve.service.ts index b4b92f30cc..25d2806e8f 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-detail-resolve.service.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-detail-resolve.service.ts @@ -10,7 +10,7 @@ export class CrisisDetailResolve implements Resolve { constructor(private cs: CrisisService, private router: Router) {} resolve(route: ActivatedRouteSnapshot): Promise|boolean { - let id = +route.params['id']; + let id = route.params['id']; return this.cs.getCrisis(id).then(crisis => { if (crisis) { diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.1.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.1.ts index 2a52513b6f..b314fb615f 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.1.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.1.ts @@ -1,5 +1,6 @@ // #docplaster // #docregion +import 'rxjs/add/operator/switchMap'; import { Component, OnInit, HostBinding, trigger, transition, animate, style, state } from '@angular/core'; @@ -12,9 +13,9 @@ import { DialogService } from '../dialog.service'; // #docregion template template: `
-

"{{editName}}"

+

"{{ editName }}"

- {{crisis.id}}
+ {{ crisis.id }}
@@ -74,21 +75,19 @@ export class CrisisDetailComponent implements OnInit { private router: Router, private route: ActivatedRoute, public dialogService: DialogService - ) { } + ) {} // #docregion ngOnInit ngOnInit() { - this.route.params.forEach((params: Params) => { - let id = +params['id']; - this.service.getCrisis(id) - .then(crisis => { - if (crisis) { - this.editName = crisis.name; - this.crisis = crisis; - } else { // id not found - this.gotoCrises(); - } - }); + this.route.params + .switchMap((params: Params) => this.service.getCrisis(params['id'])) + .subscribe((crisis: Crisis) => { + if (crisis) { + this.editName = crisis.name; + this.crisis = crisis; + } else { // id not found + this.gotoCrises(); + } }); } // #enddocregion ngOnInit diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.ts index cda3b7dc6a..d121242a13 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.ts @@ -11,9 +11,9 @@ import { DialogService } from '../dialog.service'; @Component({ template: `
-

"{{editName}}"

+

"{{ editName }}"

- {{crisis.id}}
+ {{ crisis.id }}
@@ -70,14 +70,15 @@ export class CrisisDetailComponent implements OnInit { private route: ActivatedRoute, private router: Router, public dialogService: DialogService - ) { } + ) {} // #docregion crisis-detail-resolve ngOnInit() { - this.route.data.forEach((data: { crisis: Crisis }) => { - this.editName = data.crisis.name; - this.crisis = data.crisis; - }); + this.route.data + .subscribe((data: { crisis: Crisis }) => { + this.editName = data.crisis.name; + this.crisis = data.crisis; + }); } // #enddocregion crisis-detail-resolve diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.1.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.1.ts index 80fa3483cd..53b9773212 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.1.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.1.ts @@ -1,49 +1,45 @@ // #docplaster // #docregion -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/switchMap'; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router, Params } from '@angular/router'; import { Crisis, CrisisService } from './crisis.service'; -import { Subscription } from 'rxjs/Subscription'; +import { Observable } from 'rxjs/Observable'; @Component({ // #docregion template template: `
    -
  • - {{crisis.id}} {{crisis.name}} + {{ crisis.id }} {{ crisis.name }}
`, // #enddocregion template }) -export class CrisisListComponent implements OnInit, OnDestroy { - crises: Crisis[]; +export class CrisisListComponent implements OnInit { + crises: Observable; selectedId: number; - private sub: Subscription; // #docregion relative-navigation-ctor constructor( private service: CrisisService, private route: ActivatedRoute, - private router: Router) {} + private router: Router + ) {} // #enddocregion relative-navigation-ctor ngOnInit() { - this.sub = this.route - .params - .subscribe(params => { + this.crises = this.route.params + .switchMap((params: Params) => { this.selectedId = +params['id']; - this.service.getCrises() - .then(crises => this.crises = crises); + return this.service.getCrises(); }); } - ngOnDestroy() { - this.sub.unsubscribe(); - } - // #docregion select onSelect(crisis: Crisis) { // Absolute link diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts index 350867adbc..2b52f43f57 100644 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts +++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts @@ -1,17 +1,20 @@ // #docplaster // #docregion +import 'rxjs/add/operator/switchMap'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router, Params } from '@angular/router'; +import { Observable } from 'rxjs/Observable'; + import { Crisis, CrisisService } from './crisis.service'; @Component({ template: `
    -
  • - {{crisis.id}} {{crisis.name}} + {{ crisis.id }} {{ crisis.name }}
@@ -19,25 +22,25 @@ import { Crisis, CrisisService } from './crisis.service'; ` }) export class CrisisListComponent implements OnInit { - crises: Crisis[]; - public selectedId: number; + crises: Observable; + selectedId: number; constructor( private service: CrisisService, private route: ActivatedRoute, private router: Router - ) { } + ) {} isSelected(crisis: Crisis) { return crisis.id === this.selectedId; } ngOnInit() { - this.route.params.forEach((params: Params) => { - this.selectedId = params['id']; - this.service.getCrises() - .then(crises => this.crises = crises); - }); + this.crises = this.route.params + .switchMap((params: Params) => { + this.selectedId = +params['id']; + return this.service.getCrises(); + }); } // #docregion relative-navigation diff --git a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.1.ts b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.1.ts index 90d0510bd7..93f0efaf0b 100644 --- a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.1.ts +++ b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.1.ts @@ -1,5 +1,8 @@ // #docplaster // #docregion +// #docregion rxjs-operator-import +import 'rxjs/add/operator/switchMap'; +// #enddocregion rxjs-operator-import import { Component, OnInit } from '@angular/core'; // #docregion imports import { Router, ActivatedRoute, Params } from '@angular/router'; @@ -11,9 +14,9 @@ import { Hero, HeroService } from './hero.service'; template: `

HEROES

-

"{{hero.name}}"

+

"{{ hero.name }}"

- {{hero.id}}
+ {{ hero.id }}
@@ -37,14 +40,16 @@ export class HeroDetailComponent implements OnInit { // #docregion ngOnInit ngOnInit() { - this.route.params.forEach((params: Params) => { - let id = +params['id']; // (+) converts string 'id' to a number - this.service.getHero(id).then(hero => this.hero = hero); - }); + this.route.params + // (+) converts string 'id' to a number + .switchMap((params: Params) => this.service.getHero(+params['id'])) + .subscribe((hero: Hero) => this.hero = hero); } // #enddocregion ngOnInit // #docregion gotoHeroes - gotoHeroes() { this.router.navigate(['/heroes']); } + gotoHeroes() { + this.router.navigate(['/heroes']); + } // #enddocregion gotoHeroes } diff --git a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.2.ts b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.2.ts index 07b876c79f..c3b69be965 100644 --- a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.2.ts +++ b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.2.ts @@ -9,9 +9,9 @@ import { Hero, HeroService } from './hero.service'; template: `

HEROES

-

"{{hero.name}}"

+

"{{ hero.name }}"

- {{hero.id}}
+ {{ hero.id }}
@@ -28,15 +28,20 @@ export class HeroDetailComponent implements OnInit { constructor( private route: ActivatedRoute, private router: Router, - private service: HeroService) {} + private service: HeroService + ) {} // #docregion snapshot ngOnInit() { // (+) converts string 'id' to a number let id = +this.route.snapshot.params['id']; - this.service.getHero(id).then(hero => this.hero = hero); + + this.service.getHero(id) + .then((hero: Hero) => this.hero = hero); } // #enddocregion snapshot - gotoHeroes() { this.router.navigate(['/heroes']); } + gotoHeroes() { + this.router.navigate(['/heroes']); + } } diff --git a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts index 42adbe2d98..c528651f44 100644 --- a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts +++ b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts @@ -1,5 +1,8 @@ // #docplaster // #docregion +// #docregion rxjs-operator-import +import 'rxjs/add/operator/switchMap'; +// #docregion rxjs-operator-import // #docregion route-animation-imports import { Component, OnInit, HostBinding, trigger, transition, animate, @@ -14,9 +17,9 @@ import { Hero, HeroService } from './hero.service'; template: `

HEROES

-

"{{hero.name}}"

+

"{{ hero.name }}"

- {{hero.id}}
+ {{ hero.id }}
@@ -71,15 +74,16 @@ export class HeroDetailComponent implements OnInit { constructor( private route: ActivatedRoute, private router: Router, - private service: HeroService) {} + private service: HeroService + ) {} // #enddocregion ctor // #docregion ngOnInit ngOnInit() { - this.route.params.forEach((params: Params) => { - let id = +params['id']; // (+) converts string 'id' to a number - this.service.getHero(id).then(hero => this.hero = hero); - }); + this.route.params + // (+) converts string 'id' to a number + .switchMap((params: Params) => this.service.getHero(+params['id'])) + .subscribe((hero: Hero) => this.hero = hero); } // #enddocregion ngOnInit diff --git a/public/docs/_examples/router/ts/app/heroes/hero-list.component.1.ts b/public/docs/_examples/router/ts/app/heroes/hero-list.component.1.ts index 0b7298009c..878fef4694 100644 --- a/public/docs/_examples/router/ts/app/heroes/hero-list.component.1.ts +++ b/public/docs/_examples/router/ts/app/heroes/hero-list.component.1.ts @@ -11,25 +11,26 @@ import { Hero, HeroService } from './hero.service'; template: `

HEROES

    -
  • - {{hero.id}} {{hero.name}} + {{ hero.id }} {{ hero.name }}
` // #enddocregion template }) export class HeroListComponent implements OnInit { - heroes: Hero[]; + heroes: Promise; // #docregion ctor constructor( private router: Router, - private service: HeroService) { } + private service: HeroService + ) {} // #enddocregion ctor ngOnInit() { - this.service.getHeroes().then(heroes => this.heroes = heroes); + this.heroes = this.service.getHeroes(); } // #docregion select diff --git a/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts b/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts index 068c9680d0..ff0378a836 100644 --- a/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts +++ b/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts @@ -1,6 +1,10 @@ // #docplaster // #docregion // TODO SOMEDAY: Feature Componetized like CrisisCenter +// #docregion rxjs-imports +import 'rxjs/add/operator/switchMap'; +import { Observable } from 'rxjs/Observable'; +// #enddocregion rxjs-imports import { Component, OnInit } from '@angular/core'; // #docregion import-router import { Router, ActivatedRoute, Params } from '@angular/router'; @@ -13,19 +17,19 @@ import { Hero, HeroService } from './hero.service'; template: `

HEROES

    -
  • - {{hero.id}} {{hero.name}} + {{ hero.id }} {{ hero.name }}
` // #enddocregion template }) +// #docregion ctor export class HeroListComponent implements OnInit { - heroes: Hero[]; + heroes: Observable; - // #docregion ctor private selectedId: number; constructor( @@ -36,10 +40,10 @@ export class HeroListComponent implements OnInit { // #enddocregion ctor ngOnInit() { - this.route.params.forEach((params: Params) => { + this.heroes = this.route.params + .switchMap((params: Params) => { this.selectedId = +params['id']; - this.service.getHeroes() - .then(heroes => this.heroes = heroes); + return this.service.getHeroes(); }); } // #enddocregion ctor @@ -53,6 +57,6 @@ export class HeroListComponent implements OnInit { this.router.navigate(['/hero', hero.id]); } // #enddocregion select - +// #docregion ctor } // #enddocregion diff --git a/public/docs/_examples/router/ts/app/heroes/heroes-routing.module.ts b/public/docs/_examples/router/ts/app/heroes/heroes-routing.module.ts index 96bf339394..dbee521793 100644 --- a/public/docs/_examples/router/ts/app/heroes/heroes-routing.module.ts +++ b/public/docs/_examples/router/ts/app/heroes/heroes-routing.module.ts @@ -1,18 +1,20 @@ // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { HeroListComponent } from './hero-list.component'; import { HeroDetailComponent } from './hero-detail.component'; +const heroesRoutes: Routes = [ + { path: 'heroes', component: HeroListComponent }, +// #docregion hero-detail-route + { path: 'hero/:id', component: HeroDetailComponent } +// #enddocregion hero-detail-route +]; + @NgModule({ imports: [ - RouterModule.forChild([ - { path: 'heroes', component: HeroListComponent }, - // #docregion hero-detail-route - { path: 'hero/:id', component: HeroDetailComponent } - // #enddocregion hero-detail-route - ]) + RouterModule.forChild(heroesRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/app/login-routing.module.ts b/public/docs/_examples/router/ts/app/login-routing.module.ts index 43c0e28a97..96d05e7972 100644 --- a/public/docs/_examples/router/ts/app/login-routing.module.ts +++ b/public/docs/_examples/router/ts/app/login-routing.module.ts @@ -1,15 +1,17 @@ // #docregion -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { AuthGuard } from './auth-guard.service'; -import { AuthService } from './auth.service'; -import { LoginComponent } from './login.component'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AuthGuard } from './auth-guard.service'; +import { AuthService } from './auth.service'; +import { LoginComponent } from './login.component'; + +const loginRoutes: Routes = [ + { path: 'login', component: LoginComponent } +]; @NgModule({ imports: [ - RouterModule.forChild([ - { path: 'login', component: LoginComponent } - ]) + RouterModule.forChild(loginRoutes) ], exports: [ RouterModule diff --git a/public/docs/_examples/router/ts/index.1.html b/public/docs/_examples/router/ts/index.1.html index dbf32ae565..427becd129 100644 --- a/public/docs/_examples/router/ts/index.1.html +++ b/public/docs/_examples/router/ts/index.1.html @@ -10,7 +10,7 @@ - + diff --git a/public/docs/_examples/router/ts/index.html b/public/docs/_examples/router/ts/index.html index abcbea6c31..1195b38267 100644 --- a/public/docs/_examples/router/ts/index.html +++ b/public/docs/_examples/router/ts/index.html @@ -9,7 +9,7 @@ - + diff --git a/public/docs/_examples/security/ts/index.html b/public/docs/_examples/security/ts/index.html index 16eeeb2b2a..936c716eff 100644 --- a/public/docs/_examples/security/ts/index.html +++ b/public/docs/_examples/security/ts/index.html @@ -7,7 +7,7 @@ - + diff --git a/public/docs/_examples/server-communication/dart/pubspec.yaml b/public/docs/_examples/server-communication/dart/pubspec.yaml index e3cc493935..fe5edb1a32 100644 --- a/public/docs/_examples/server-communication/dart/pubspec.yaml +++ b/public/docs/_examples/server-communication/dart/pubspec.yaml @@ -6,12 +6,13 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^1.0.1 http: ^0.11.0 jsonpadding: ^0.1.0 stream_transformers: ^0.3.0 http_in_memory_web_api: ^0.2.0 +dev_dependencies: + browser: ^0.10.0 + dart_to_js_script_rewriter: ^1.0.1 # #docregion transformers transformers: - angular2: diff --git a/public/docs/_examples/server-communication/ts/index.html b/public/docs/_examples/server-communication/ts/index.html index 6b99fc5242..84bb0d53fa 100644 --- a/public/docs/_examples/server-communication/ts/index.html +++ b/public/docs/_examples/server-communication/ts/index.html @@ -7,7 +7,7 @@ - + diff --git a/public/docs/_examples/structural-directives/dart/pubspec.yaml b/public/docs/_examples/structural-directives/dart/pubspec.yaml index 5d6f88d490..c324c13cdc 100644 --- a/public/docs/_examples/structural-directives/dart/pubspec.yaml +++ b/public/docs/_examples/structural-directives/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/structural-directives/ts/index.html b/public/docs/_examples/structural-directives/ts/index.html index 2dc2548cc4..15dbbd7652 100644 --- a/public/docs/_examples/structural-directives/ts/index.html +++ b/public/docs/_examples/structural-directives/ts/index.html @@ -7,7 +7,7 @@ - + diff --git a/public/docs/_examples/style-guide/ts/index.html b/public/docs/_examples/style-guide/ts/index.html index 44a280de44..b71cd55c69 100644 --- a/public/docs/_examples/style-guide/ts/index.html +++ b/public/docs/_examples/style-guide/ts/index.html @@ -9,7 +9,7 @@ - + diff --git a/public/docs/_examples/styleguide/ts/index.html b/public/docs/_examples/styleguide/ts/index.html index 5983457e07..8f1330fe94 100644 --- a/public/docs/_examples/styleguide/ts/index.html +++ b/public/docs/_examples/styleguide/ts/index.html @@ -7,7 +7,7 @@ - + diff --git a/public/docs/_examples/template-syntax/dart/lib/app_component.dart b/public/docs/_examples/template-syntax/dart/lib/app_component.dart index 6a3def5aa4..4be7533fcc 100644 --- a/public/docs/_examples/template-syntax/dart/lib/app_component.dart +++ b/public/docs/_examples/template-syntax/dart/lib/app_component.dart @@ -7,7 +7,8 @@ import 'package:angular2/common.dart'; import 'hero.dart'; import 'hero_detail_component.dart'; -import 'my_click_directive.dart'; +import 'click_directive.dart'; +import 'sizer_component.dart'; enum Color { red, green, blue } @@ -18,7 +19,8 @@ enum Color { red, green, blue } HeroDetailComponent, BigHeroDetailComponent, MyClickDirective, - MyClickDirective2 + MyClickDirective2, + MySizerComponent ]) class AppComponent implements OnInit, AfterViewInit { @override @@ -165,6 +167,7 @@ class AppComponent implements OnInit, AfterViewInit { bool isItalic = false; bool isBold = false; String fontSize = 'large'; + String fontSizePx = '14'; Map setStyle() { return { diff --git a/public/docs/_examples/template-syntax/dart/lib/app_component.html b/public/docs/_examples/template-syntax/dart/lib/app_component.html index 9fd72765ed..3255a02ff6 100644 --- a/public/docs/_examples/template-syntax/dart/lib/app_component.html +++ b/public/docs/_examples/template-syntax/dart/lib/app_component.html @@ -14,7 +14,7 @@

Event Binding
- +Two-way Binding

Directives
@@ -242,9 +242,6 @@ button - - -
@@ -262,7 +259,7 @@ button
Bad curly
+ [class]="badCurly">Bad curly
@@ -309,9 +306,9 @@ button
- +
click with myClick
- + {{clickMessage}}
@@ -349,6 +346,24 @@ button


+top + +

Two-way Binding

+
+ + +
Resizable Text
+ + +
+
+
+

De-sugared two-way binding

+ + + +
+

top @@ -746,7 +761,7 @@ bindon-ngModel
- {{product['price'] | currency:'USD':false}} + {{product['price'] | currency:'USD':true}}
top diff --git a/public/docs/_examples/template-syntax/dart/lib/my_click_directive.dart b/public/docs/_examples/template-syntax/dart/lib/click_directive.dart similarity index 81% rename from public/docs/_examples/template-syntax/dart/lib/my_click_directive.dart rename to public/docs/_examples/template-syntax/dart/lib/click_directive.dart index 0980478f29..101b9eb5c6 100644 --- a/public/docs/_examples/template-syntax/dart/lib/my_click_directive.dart +++ b/public/docs/_examples/template-syntax/dart/lib/click_directive.dart @@ -5,11 +5,11 @@ import 'package:angular2/core.dart'; @Directive(selector: '[myClick]') class MyClickDirective { - // #docregion my-click-output-1 + // #docregion output-myClick // @Output(alias) [type info] propertyName = ... @Output('myClick') final EventEmitter clicks = new EventEmitter(); - // #enddocregion my-click-output-1 + // #enddocregion output-myClick bool _toggle = false; MyClickDirective(ElementRef el) { @@ -21,14 +21,14 @@ class MyClickDirective { } } -// #docregion my-click-output-2 +// #docregion output-myClick2 @Directive( -// #enddocregion my-click-output-2 +// #enddocregion output-myClick2 selector: '[myClick2]', -// #docregion my-click-output-2 +// #docregion output-myClick2 // ... outputs: const ['clicks:myClick']) // propertyName:alias -// #enddocregion my-click-output-2 +// #enddocregion output-myClick2 class MyClickDirective2 { final EventEmitter clicks = new EventEmitter(); bool _toggle = false; diff --git a/public/docs/_examples/template-syntax/dart/lib/sizer_component.dart b/public/docs/_examples/template-syntax/dart/lib/sizer_component.dart new file mode 100644 index 0000000000..84dbc1d9ff --- /dev/null +++ b/public/docs/_examples/template-syntax/dart/lib/sizer_component.dart @@ -0,0 +1,30 @@ +// #docregion +import 'dart:math'; +import 'package:angular2/core.dart'; + +@Component( + selector: 'my-sizer', + template: ''' +
+ + + +
''') +class MySizerComponent { + static final defaultPxSize = 14; + + @Input() + String size; + + @Output() + var sizeChange = new EventEmitter(); + + void dec() => resize(-1); + void inc() => resize(1); + + void resize(num delta) { + final numSize = num.parse(size, (_) => defaultPxSize); + size = min(40, max(8, numSize + delta)).toString(); + sizeChange.emit(size); + } +} diff --git a/public/docs/_examples/template-syntax/dart/pubspec.yaml b/public/docs/_examples/template-syntax/dart/pubspec.yaml index 17ccc01d50..2b6f478f0d 100644 --- a/public/docs/_examples/template-syntax/dart/pubspec.yaml +++ b/public/docs/_examples/template-syntax/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/template-syntax/e2e-spec.ts b/public/docs/_examples/template-syntax/e2e-spec.ts index b8621c4d2d..71f1c58165 100644 --- a/public/docs/_examples/template-syntax/e2e-spec.ts +++ b/public/docs/_examples/template-syntax/e2e-spec.ts @@ -31,14 +31,13 @@ describe('Template Syntax', function () { expect(specialButtonEle.getAttribute('style')).toMatch('color: red'); }); - it('should two-way bind to sizer', function () { - let buttons = element.all(by.css('div#two-way-1 my-sizer button')); - let input = element(by.css('input#fontsize')); - - input.getAttribute('value').then(size => { - buttons.get(1).click(); - browser.waitForAngular(); - expect(input.getAttribute('value')).toEqual((+size + 1).toString()); - }); + it('should two-way bind to sizer', async () => { + let div = element(by.css('div#two-way-1')); + let incButton = div.element(by.buttonText('+')); + let input = div.element(by.css('input')); + let initSize = await input.getAttribute('value'); + incButton.click(); + expect(input.getAttribute('value')).toEqual((+initSize + 1).toString()); }); }); + diff --git a/public/docs/_examples/template-syntax/ts/app/app.component.html b/public/docs/_examples/template-syntax/ts/app/app.component.html index d844154f58..30a80412c7 100644 --- a/public/docs/_examples/template-syntax/ts/app/app.component.html +++ b/public/docs/_examples/template-syntax/ts/app/app.component.html @@ -305,10 +305,10 @@ button
- - + +
click with myClick
- + {{clickMessage}}
@@ -351,21 +351,22 @@ button

Two-way Binding

- -
Resizable Text
+ +
Resizable Text
- +

De-sugared two-way binding

- +


top +

NgModel (two-way) Binding

@@ -428,6 +429,18 @@ bindon-ngModel

NgStyle Binding

+ +
+

Change style of this text!

+ + | + | + + +

Style set to: '{{styleP.style.cssText}}'

+
+ +
This div is x-large. diff --git a/public/docs/_examples/template-syntax/ts/app/app.component.ts b/public/docs/_examples/template-syntax/ts/app/app.component.ts index 072c634162..77221587a7 100644 --- a/public/docs/_examples/template-syntax/ts/app/app.component.ts +++ b/public/docs/_examples/template-syntax/ts/app/app.component.ts @@ -50,8 +50,6 @@ export class AppComponent implements AfterViewInit, OnInit { this.alert('Deleted hero: ' + (hero && hero.firstName)); } - fontSize = 10; - // #docregion evil-title evilTitle = 'Template Syntax'; // #enddocregion evil-title @@ -180,6 +178,21 @@ export class AppComponent implements AfterViewInit, OnInit { } // #enddocregion setStyles + // #docregion NgStyle + isItalic = false; + isBold = false; + fontSize: string = 'large'; + fontSizePx: number | string = 14; + + setStyle() { + return { + 'font-style': this.isItalic ? 'italic' : 'normal', + 'font-weight': this.isBold ? 'bold' : 'normal', + 'font-size': this.fontSize + }; + } + // #enddocregion NgStyle + toeChoice = ''; toeChooser(picker: HTMLFieldSetElement) { let choices = picker.children; diff --git a/public/docs/_examples/template-syntax/ts/app/app.module.ts b/public/docs/_examples/template-syntax/ts/app/app.module.ts index db940fad08..712b613daf 100644 --- a/public/docs/_examples/template-syntax/ts/app/app.module.ts +++ b/public/docs/_examples/template-syntax/ts/app/app.module.ts @@ -4,7 +4,7 @@ import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { BigHeroDetailComponent, HeroDetailComponent } from './hero-detail.component'; -import { MyClickDirective, MyClickDirective2 } from './my-click.directive'; +import { ClickDirective, ClickDirective2 } from './click.directive'; import { SizerComponent } from './sizer.component'; @NgModule({ @@ -16,8 +16,8 @@ import { SizerComponent } from './sizer.component'; AppComponent, BigHeroDetailComponent, HeroDetailComponent, - MyClickDirective, - MyClickDirective2, + ClickDirective, + ClickDirective2, SizerComponent ], bootstrap: [ AppComponent ] diff --git a/public/docs/_examples/template-syntax/ts/app/my-click.directive.ts b/public/docs/_examples/template-syntax/ts/app/click.directive.ts similarity index 76% rename from public/docs/_examples/template-syntax/ts/app/my-click.directive.ts rename to public/docs/_examples/template-syntax/ts/app/click.directive.ts index 1f552277bf..09757bfeaf 100644 --- a/public/docs/_examples/template-syntax/ts/app/my-click.directive.ts +++ b/public/docs/_examples/template-syntax/ts/app/click.directive.ts @@ -3,10 +3,10 @@ import { Directive, ElementRef, EventEmitter, Output } from '@angular/core'; @Directive({selector: '[myClick]'}) -export class MyClickDirective { - // #docregion my-click-output-1 +export class ClickDirective { + // #docregion output-myClick @Output('myClick') clicks = new EventEmitter(); // @Output(alias) propertyName = ... - // #enddocregion my-click-output-1 + // #enddocregion output-myClick toggle = false; @@ -19,15 +19,15 @@ export class MyClickDirective { } } -// #docregion my-click-output-2 +// #docregion output-myClick2 @Directive({ -// #enddocregion my-click-output-2 + // #enddocregion output-myClick2 selector: '[myClick2]', -// #docregion my-click-output-2 + // #docregion output-myClick2 outputs: ['clicks:myClick'] // propertyName:alias }) -// #enddocregion my-click-output-2 -export class MyClickDirective2 { +// #enddocregion output-myClick2 +export class ClickDirective2 { clicks = new EventEmitter(); toggle = false; diff --git a/public/docs/_examples/template-syntax/ts/app/sizer.component.ts b/public/docs/_examples/template-syntax/ts/app/sizer.component.ts index cf0ef4af47..b6065c8cd1 100644 --- a/public/docs/_examples/template-syntax/ts/app/sizer.component.ts +++ b/public/docs/_examples/template-syntax/ts/app/sizer.component.ts @@ -11,15 +11,14 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
` }) export class SizerComponent { - @Input() size: number; + @Input() size: number | string; @Output() sizeChange = new EventEmitter(); dec() { this.resize(-1); } inc() { this.resize(+1); } resize(delta: number) { - const size = +this.size + delta; - this.size = Math.min(40, Math.max(8, size)); + this.size = Math.min(40, Math.max(8, +this.size + delta)); this.sizeChange.emit(this.size); } } diff --git a/public/docs/_examples/template-syntax/ts/index.html b/public/docs/_examples/template-syntax/ts/index.html index d3a4ec6aa6..e67e1871fd 100644 --- a/public/docs/_examples/template-syntax/ts/index.html +++ b/public/docs/_examples/template-syntax/ts/index.html @@ -7,7 +7,7 @@ - + diff --git a/public/docs/_examples/testing/ts/1st-specs.plnkr.json b/public/docs/_examples/testing/ts/1st-specs.plnkr.json index 945ec90060..1d4dd58afa 100644 --- a/public/docs/_examples/testing/ts/1st-specs.plnkr.json +++ b/public/docs/_examples/testing/ts/1st-specs.plnkr.json @@ -8,5 +8,6 @@ "1st-specs.html" ], "main": "1st-specs.html", - "tags": ["testing"] + "tags": ["testing"], + "includeSystemConfig": true } diff --git a/public/docs/_examples/testing/ts/app-specs.plnkr.json b/public/docs/_examples/testing/ts/app-specs.plnkr.json index afd126bb45..18dd58dec9 100644 --- a/public/docs/_examples/testing/ts/app-specs.plnkr.json +++ b/public/docs/_examples/testing/ts/app-specs.plnkr.json @@ -19,5 +19,6 @@ "app-specs.html" ], "main": "app-specs.html", - "tags": ["testing"] + "tags": ["testing"], + "includeSystemConfig": true } diff --git a/public/docs/_examples/testing/ts/app/bag/bag.ts b/public/docs/_examples/testing/ts/app/bag/bag.ts index 1c9a005b08..0dc4453e77 100644 --- a/public/docs/_examples/testing/ts/app/bag/bag.ts +++ b/public/docs/_examples/testing/ts/app/bag/bag.ts @@ -152,7 +152,7 @@ export class InputComponent { // selector: 'input[value]', // host: { // '[value]': 'value', -// '(input)': 'valueChange.next($event.target.value)' +// '(input)': 'valueChange.emit($event.target.value)' // }, // inputs: ['value'], // outputs: ['valueChange'] @@ -173,7 +173,7 @@ export class InputValueBinderDirective { valueChange: EventEmitter = new EventEmitter(); @HostListener('input', ['$event.target.value']) - onInput(value: any) { this.valueChange.next(value); } + onInput(value: any) { this.valueChange.emit(value); } } @Component({ diff --git a/public/docs/_examples/testing/ts/app/dashboard/dashboard-hero.component.ts b/public/docs/_examples/testing/ts/app/dashboard/dashboard-hero.component.ts index 26daf8bb54..6363058f75 100644 --- a/public/docs/_examples/testing/ts/app/dashboard/dashboard-hero.component.ts +++ b/public/docs/_examples/testing/ts/app/dashboard/dashboard-hero.component.ts @@ -13,6 +13,6 @@ import { Hero } from '../model'; export class DashboardHeroComponent { @Input() hero: Hero; @Output() selected = new EventEmitter(); - click() { this.selected.next(this.hero); } + click() { this.selected.emit(this.hero); } } // #enddocregion component diff --git a/public/docs/_examples/testing/ts/bag-specs.plnkr.json b/public/docs/_examples/testing/ts/bag-specs.plnkr.json index 89d86da28a..b176c00cc5 100644 --- a/public/docs/_examples/testing/ts/bag-specs.plnkr.json +++ b/public/docs/_examples/testing/ts/bag-specs.plnkr.json @@ -16,5 +16,6 @@ "bag-specs.html" ], "main": "bag-specs.html", - "tags": ["testing"] + "tags": ["testing"], + "includeSystemConfig": true } diff --git a/public/docs/_examples/testing/ts/bag.html b/public/docs/_examples/testing/ts/bag.html index 35ff270025..d62d837f47 100644 --- a/public/docs/_examples/testing/ts/bag.html +++ b/public/docs/_examples/testing/ts/bag.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/testing/ts/browser-test-shim.js b/public/docs/_examples/testing/ts/browser-test-shim.js index efca6c3554..1cbabc3f64 100644 --- a/public/docs/_examples/testing/ts/browser-test-shim.js +++ b/public/docs/_examples/testing/ts/browser-test-shim.js @@ -33,8 +33,6 @@ System.config({ }, }); -document['noBootstrap'] = true; // do not run system.config.web.js bootstrap - System.import('systemjs.config.js') .then(importSystemJsExtras) .then(initTestBed) diff --git a/public/docs/_examples/testing/ts/index.html b/public/docs/_examples/testing/ts/index.html index b50b69ec18..019b2319bf 100644 --- a/public/docs/_examples/testing/ts/index.html +++ b/public/docs/_examples/testing/ts/index.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/toh-1/dart/pubspec.yaml b/public/docs/_examples/toh-1/dart/pubspec.yaml index af57cdc274..1949bed728 100644 --- a/public/docs/_examples/toh-1/dart/pubspec.yaml +++ b/public/docs/_examples/toh-1/dart/pubspec.yaml @@ -1,11 +1,12 @@ # #docregion -name: angular2_tour_of_heroes +name: angular_tour_of_heroes description: Tour of Heroes version: 0.0.1 environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/toh-1/dart/web/main.dart b/public/docs/_examples/toh-1/dart/web/main.dart index dbf48b9c70..c7ff5cd60b 100644 --- a/public/docs/_examples/toh-1/dart/web/main.dart +++ b/public/docs/_examples/toh-1/dart/web/main.dart @@ -1,7 +1,7 @@ // #docregion pt1 import 'package:angular2/platform/browser.dart'; -import 'package:angular2_tour_of_heroes/app_component.dart'; +import 'package:angular_tour_of_heroes/app_component.dart'; void main() { bootstrap(AppComponent); diff --git a/public/docs/_examples/toh-1/ts/index.html b/public/docs/_examples/toh-1/ts/index.html index 4445befc9a..bed95dc8fa 100644 --- a/public/docs/_examples/toh-1/ts/index.html +++ b/public/docs/_examples/toh-1/ts/index.html @@ -6,7 +6,7 @@ - + diff --git a/public/docs/_examples/toh-2/dart/pubspec.yaml b/public/docs/_examples/toh-2/dart/pubspec.yaml index af57cdc274..1949bed728 100644 --- a/public/docs/_examples/toh-2/dart/pubspec.yaml +++ b/public/docs/_examples/toh-2/dart/pubspec.yaml @@ -1,11 +1,12 @@ # #docregion -name: angular2_tour_of_heroes +name: angular_tour_of_heroes description: Tour of Heroes version: 0.0.1 environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/toh-2/dart/web/main.dart b/public/docs/_examples/toh-2/dart/web/main.dart index ed2bb7156f..2b35525f8d 100644 --- a/public/docs/_examples/toh-2/dart/web/main.dart +++ b/public/docs/_examples/toh-2/dart/web/main.dart @@ -1,6 +1,6 @@ import 'package:angular2/platform/browser.dart'; -import 'package:angular2_tour_of_heroes/app_component.dart'; +import 'package:angular_tour_of_heroes/app_component.dart'; void main() { bootstrap(AppComponent); diff --git a/public/docs/_examples/toh-2/ts/index.html b/public/docs/_examples/toh-2/ts/index.html index 4445befc9a..bed95dc8fa 100644 --- a/public/docs/_examples/toh-2/ts/index.html +++ b/public/docs/_examples/toh-2/ts/index.html @@ -6,7 +6,7 @@ - + diff --git a/public/docs/_examples/toh-3/dart/pubspec.yaml b/public/docs/_examples/toh-3/dart/pubspec.yaml index af57cdc274..1949bed728 100644 --- a/public/docs/_examples/toh-3/dart/pubspec.yaml +++ b/public/docs/_examples/toh-3/dart/pubspec.yaml @@ -1,11 +1,12 @@ # #docregion -name: angular2_tour_of_heroes +name: angular_tour_of_heroes description: Tour of Heroes version: 0.0.1 environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/toh-3/dart/web/main.dart b/public/docs/_examples/toh-3/dart/web/main.dart index 81c22cd91d..f77be42dce 100644 --- a/public/docs/_examples/toh-3/dart/web/main.dart +++ b/public/docs/_examples/toh-3/dart/web/main.dart @@ -1,7 +1,7 @@ // #docregion pt1 import 'package:angular2/platform/browser.dart'; -import 'package:angular2_tour_of_heroes/app_component.dart'; +import 'package:angular_tour_of_heroes/app_component.dart'; main() { bootstrap(AppComponent); diff --git a/public/docs/_examples/toh-3/ts/index.html b/public/docs/_examples/toh-3/ts/index.html index 4445befc9a..bed95dc8fa 100644 --- a/public/docs/_examples/toh-3/ts/index.html +++ b/public/docs/_examples/toh-3/ts/index.html @@ -6,7 +6,7 @@ - + diff --git a/public/docs/_examples/toh-4/dart/pubspec.yaml b/public/docs/_examples/toh-4/dart/pubspec.yaml index af57cdc274..1949bed728 100644 --- a/public/docs/_examples/toh-4/dart/pubspec.yaml +++ b/public/docs/_examples/toh-4/dart/pubspec.yaml @@ -1,11 +1,12 @@ # #docregion -name: angular2_tour_of_heroes +name: angular_tour_of_heroes description: Tour of Heroes version: 0.0.1 environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/toh-4/dart/web/main.dart b/public/docs/_examples/toh-4/dart/web/main.dart index ed2bb7156f..2b35525f8d 100644 --- a/public/docs/_examples/toh-4/dart/web/main.dart +++ b/public/docs/_examples/toh-4/dart/web/main.dart @@ -1,6 +1,6 @@ import 'package:angular2/platform/browser.dart'; -import 'package:angular2_tour_of_heroes/app_component.dart'; +import 'package:angular_tour_of_heroes/app_component.dart'; void main() { bootstrap(AppComponent); diff --git a/public/docs/_examples/toh-4/dart/web/main_1.dart b/public/docs/_examples/toh-4/dart/web/main_1.dart index 76e71e02a2..40c663bd13 100644 --- a/public/docs/_examples/toh-4/dart/web/main_1.dart +++ b/public/docs/_examples/toh-4/dart/web/main_1.dart @@ -1,6 +1,6 @@ import 'package:angular2/platform/browser.dart'; -import 'package:angular2_tour_of_heroes/app_component_1.dart'; +import 'package:angular_tour_of_heroes/app_component_1.dart'; void main() { bootstrap(AppComponent); diff --git a/public/docs/_examples/toh-4/ts/index.html b/public/docs/_examples/toh-4/ts/index.html index 4445befc9a..bed95dc8fa 100644 --- a/public/docs/_examples/toh-4/ts/index.html +++ b/public/docs/_examples/toh-4/ts/index.html @@ -6,7 +6,7 @@ - + diff --git a/public/docs/_examples/toh-5/dart/lib/dashboard_component.dart b/public/docs/_examples/toh-5/dart/lib/dashboard_component.dart index bc2293cec1..1731bf4d0e 100644 --- a/public/docs/_examples/toh-5/dart/lib/dashboard_component.dart +++ b/public/docs/_examples/toh-5/dart/lib/dashboard_component.dart @@ -4,21 +4,27 @@ import 'dart:async'; import 'package:angular2/core.dart'; +// #docregion import-router +import 'package:angular2/router.dart'; +// #enddocregion import-router import 'hero.dart'; import 'hero_service.dart'; // #enddocregion imports +// #docregion metadata @Component( selector: 'my-dashboard', // #docregion templateUrl templateUrl: 'dashboard_component.html', // #enddocregion templateUrl // #docregion css - styleUrls: const ['dashboard_component.css'] + styleUrls: const ['dashboard_component.css'], // #enddocregion css + directives: const [ROUTER_DIRECTIVES], ) -// #docregion component +// #enddocregion metadata +// #docregion class, component class DashboardComponent implements OnInit { List heroes; @@ -26,11 +32,9 @@ class DashboardComponent implements OnInit { final HeroService _heroService; DashboardComponent(this._heroService); - // #enddocregion ctor Future ngOnInit() async { heroes = (await _heroService.getHeroes()).skip(1).take(4).toList(); } } -// #enddocregion component diff --git a/public/docs/_examples/toh-5/dart/lib/dashboard_component.html b/public/docs/_examples/toh-5/dart/lib/dashboard_component.html index 49e77c460c..f48c102949 100644 --- a/public/docs/_examples/toh-5/dart/lib/dashboard_component.html +++ b/public/docs/_examples/toh-5/dart/lib/dashboard_component.html @@ -2,7 +2,7 @@

Top Heroes

- +

{{hero.name}}

diff --git a/public/docs/_examples/toh-5/dart/lib/dashboard_component.1.html b/public/docs/_examples/toh-5/dart/lib/dashboard_component_1.html similarity index 100% rename from public/docs/_examples/toh-5/dart/lib/dashboard_component.1.html rename to public/docs/_examples/toh-5/dart/lib/dashboard_component_1.html diff --git a/public/docs/_examples/toh-5/dart/lib/hero_detail_component.dart b/public/docs/_examples/toh-5/dart/lib/hero_detail_component.dart index a99528cbaa..df03c092f3 100644 --- a/public/docs/_examples/toh-5/dart/lib/hero_detail_component.dart +++ b/public/docs/_examples/toh-5/dart/lib/hero_detail_component.dart @@ -2,12 +2,12 @@ // #docregion , v2 // #docregion added-imports import 'dart:async'; -import 'dart:html' show window; // #enddocregion added-imports import 'package:angular2/core.dart'; // #docregion added-imports import 'package:angular2/router.dart'; +import 'package:angular2/platform/common.dart'; // #enddocregion added-imports import 'hero.dart'; @@ -17,9 +17,9 @@ import 'hero_service.dart'; @Component( selector: 'my-hero-detail', - // #docregion templateUrl + // #docregion metadata, templateUrl templateUrl: 'hero_detail_component.html', - // #enddocregion templateUrl, v2 + // #enddocregion metadata, templateUrl, v2 styleUrls: const ['hero_detail_component.css'] // #docregion v2 ) @@ -30,8 +30,9 @@ class HeroDetailComponent implements OnInit { // #docregion ctor final HeroService _heroService; final RouteParams _routeParams; + final Location _location; - HeroDetailComponent(this._heroService, this._routeParams); + HeroDetailComponent(this._heroService, this._routeParams, this._location); // #enddocregion ctor // #docregion ngOnInit @@ -44,7 +45,7 @@ class HeroDetailComponent implements OnInit { // #docregion goBack void goBack() { - window.history.back(); + _location.back(); } // #enddocregion goBack } diff --git a/public/docs/_examples/toh-5/dart/lib/heroes_component.dart b/public/docs/_examples/toh-5/dart/lib/heroes_component.dart index e19c3ab3be..2e0eddd076 100644 --- a/public/docs/_examples/toh-5/dart/lib/heroes_component.dart +++ b/public/docs/_examples/toh-5/dart/lib/heroes_component.dart @@ -41,9 +41,11 @@ class HeroesComponent implements OnInit { selectedHero = hero; } + // #docregion gotoDetail Future gotoDetail() => _router.navigate([ 'HeroDetail', {'id': selectedHero.id.toString()} ]); + // #enddocregion gotoDetail // #docregion renaming } diff --git a/public/docs/_examples/toh-5/dart/pubspec.yaml b/public/docs/_examples/toh-5/dart/pubspec.yaml index af57cdc274..1949bed728 100644 --- a/public/docs/_examples/toh-5/dart/pubspec.yaml +++ b/public/docs/_examples/toh-5/dart/pubspec.yaml @@ -1,11 +1,12 @@ # #docregion -name: angular2_tour_of_heroes +name: angular_tour_of_heroes description: Tour of Heroes version: 0.0.1 environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/toh-5/dart/web/main.dart b/public/docs/_examples/toh-5/dart/web/main.dart index ed2bb7156f..2b35525f8d 100644 --- a/public/docs/_examples/toh-5/dart/web/main.dart +++ b/public/docs/_examples/toh-5/dart/web/main.dart @@ -1,6 +1,6 @@ import 'package:angular2/platform/browser.dart'; -import 'package:angular2_tour_of_heroes/app_component.dart'; +import 'package:angular_tour_of_heroes/app_component.dart'; void main() { bootstrap(AppComponent); diff --git a/public/docs/_examples/toh-5/ts/app/dashboard.component.1.ts b/public/docs/_examples/toh-5/ts/app/dashboard.component.1.ts index 430a30ebbe..3c92b205c8 100644 --- a/public/docs/_examples/toh-5/ts/app/dashboard.component.1.ts +++ b/public/docs/_examples/toh-5/ts/app/dashboard.component.1.ts @@ -6,4 +6,3 @@ import { Component } from '@angular/core'; template: '

My Dashboard

' }) export class DashboardComponent { } - diff --git a/public/docs/_examples/toh-5/ts/app/dashboard.component.ts b/public/docs/_examples/toh-5/ts/app/dashboard.component.ts index cb5cfc5b82..9311a74395 100644 --- a/public/docs/_examples/toh-5/ts/app/dashboard.component.ts +++ b/public/docs/_examples/toh-5/ts/app/dashboard.component.ts @@ -33,4 +33,3 @@ export class DashboardComponent implements OnInit { .then(heroes => this.heroes = heroes.slice(1, 5)); } } -// #enddocregion class diff --git a/public/docs/_examples/toh-5/ts/app/hero-detail.component.html b/public/docs/_examples/toh-5/ts/app/hero-detail.component.html index cf96fc2169..8f2ff9d90c 100644 --- a/public/docs/_examples/toh-5/ts/app/hero-detail.component.html +++ b/public/docs/_examples/toh-5/ts/app/hero-detail.component.html @@ -11,4 +11,4 @@ -
\ No newline at end of file +
diff --git a/public/docs/_examples/toh-5/ts/app/hero-detail.component.ts b/public/docs/_examples/toh-5/ts/app/hero-detail.component.ts index 3ca01d2361..3557aa31d5 100644 --- a/public/docs/_examples/toh-5/ts/app/hero-detail.component.ts +++ b/public/docs/_examples/toh-5/ts/app/hero-detail.component.ts @@ -1,5 +1,7 @@ // #docplaster -// #docregion , v2 +// #docregion , v2, rxjs-import +import 'rxjs/add/operator/switchMap'; +// #enddocregion rxjs-import import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Params } from '@angular/router'; import { Location } from '@angular/common'; @@ -31,11 +33,9 @@ export class HeroDetailComponent implements OnInit { // #docregion ngOnInit ngOnInit(): void { - this.route.params.forEach((params: Params) => { - let id = +params['id']; - this.heroService.getHero(id) - .then(hero => this.hero = hero); - }); + this.route.params + .switchMap((params: Params) => this.heroService.getHero(+params['id'])) + .subscribe(hero => this.hero = hero); } // #enddocregion ngOnInit diff --git a/public/docs/_examples/toh-5/ts/index.html b/public/docs/_examples/toh-5/ts/index.html index f8383d0c94..e23c1d9c60 100644 --- a/public/docs/_examples/toh-5/ts/index.html +++ b/public/docs/_examples/toh-5/ts/index.html @@ -14,7 +14,7 @@ - + diff --git a/public/docs/_examples/toh-6/dart/lib/app_component.dart b/public/docs/_examples/toh-6/dart/lib/app_component.dart index ecf2bf4f3c..262f54b8ad 100644 --- a/public/docs/_examples/toh-6/dart/lib/app_component.dart +++ b/public/docs/_examples/toh-6/dart/lib/app_component.dart @@ -3,11 +3,11 @@ import 'package:angular2/core.dart'; import 'package:angular2/router.dart'; -import 'package:angular2_tour_of_heroes/heroes_component.dart'; -import 'package:angular2_tour_of_heroes/hero_service.dart'; -import 'package:angular2_tour_of_heroes/dashboard_component.dart'; +import 'package:angular_tour_of_heroes/heroes_component.dart'; +import 'package:angular_tour_of_heroes/hero_service.dart'; +import 'package:angular_tour_of_heroes/dashboard_component.dart'; // #docregion hero-detail-import -import 'package:angular2_tour_of_heroes/hero_detail_component.dart'; +import 'package:angular_tour_of_heroes/hero_detail_component.dart'; // #enddocregion hero-detail-import @Component( diff --git a/public/docs/_examples/toh-6/dart/pubspec.yaml b/public/docs/_examples/toh-6/dart/pubspec.yaml index 9f4b826c5c..07886203ce 100644 --- a/public/docs/_examples/toh-6/dart/pubspec.yaml +++ b/public/docs/_examples/toh-6/dart/pubspec.yaml @@ -1,5 +1,5 @@ # #docregion , additions -name: angular2_tour_of_heroes +name: angular_tour_of_heroes # #enddocregion additions description: Tour of Heroes version: 0.0.1 @@ -8,12 +8,13 @@ environment: # #docregion additions dependencies: angular2: ^2.0.0 + http: ^0.11.0 + stream_transformers: ^0.3.0 # #enddocregion additions +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 # #docregion additions - http: ^0.11.0 - stream_transformers: ^0.3.0 transformers: - angular2: # #enddocregion additions diff --git a/public/docs/_examples/toh-6/dart/web/main.dart b/public/docs/_examples/toh-6/dart/web/main.dart index 89f2225150..d77da2b613 100644 --- a/public/docs/_examples/toh-6/dart/web/main.dart +++ b/public/docs/_examples/toh-6/dart/web/main.dart @@ -2,9 +2,9 @@ // #docregion , v1, v2 import 'package:angular2/core.dart'; import 'package:angular2/platform/browser.dart'; -import 'package:angular2_tour_of_heroes/app_component.dart'; +import 'package:angular_tour_of_heroes/app_component.dart'; // #enddocregion v1 -import 'package:angular2_tour_of_heroes/in_memory_data_service.dart'; +import 'package:angular_tour_of_heroes/in_memory_data_service.dart'; import 'package:http/http.dart'; void main() { diff --git a/public/docs/_examples/toh-6/ts/app/hero-detail.component.ts b/public/docs/_examples/toh-6/ts/app/hero-detail.component.ts index 001b34baf7..a0342415f2 100644 --- a/public/docs/_examples/toh-6/ts/app/hero-detail.component.ts +++ b/public/docs/_examples/toh-6/ts/app/hero-detail.component.ts @@ -1,4 +1,5 @@ // #docregion +import 'rxjs/add/operator/switchMap'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Params } from '@angular/router'; import { Location } from '@angular/common'; @@ -22,11 +23,9 @@ export class HeroDetailComponent implements OnInit { ) {} ngOnInit(): void { - this.route.params.forEach((params: Params) => { - let id = +params['id']; - this.heroService.getHero(id) - .then(hero => this.hero = hero); - }); + this.route.params + .switchMap((params: Params) => this.heroService.getHero(+params['id'])) + .subscribe(hero => this.hero = hero); } // #docregion save diff --git a/public/docs/_examples/toh-6/ts/app/main.ts b/public/docs/_examples/toh-6/ts/app/main.ts index 091a7d82a7..961a226688 100644 --- a/public/docs/_examples/toh-6/ts/app/main.ts +++ b/public/docs/_examples/toh-6/ts/app/main.ts @@ -1,6 +1,6 @@ // #docregion -// main entry point import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + import { AppModule } from './app.module'; platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/toh-6/ts/index.html b/public/docs/_examples/toh-6/ts/index.html index 12c9ee46df..a79d7feca8 100644 --- a/public/docs/_examples/toh-6/ts/index.html +++ b/public/docs/_examples/toh-6/ts/index.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-bootstrap/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-bootstrap/app.module.ts deleted file mode 100644 index 6ac76407b1..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-bootstrap/app.module.ts +++ /dev/null @@ -1,29 +0,0 @@ -declare var angular: any; -// #docregion ngmodule -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -@NgModule({ - imports: [ BrowserModule ] -}) -export class AppModule {} -// #enddocregion ngmodule -angular.module('heroApp', []) - .controller('MainCtrl', function() { - this.message = 'Hello world'; - }); - - -// #docregion bootstrap -import { UpgradeAdapter } from '@angular/upgrade'; - -// #enddocregion bootstrap - -// This blank is expected to trigger the docplaster - -// #docregion bootstrap - -const upgradeAdapter = new UpgradeAdapter(AppModule); - -upgradeAdapter.bootstrap(document.body, ['heroApp'], {strictDi: true}); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/app.module.ts deleted file mode 100644 index fdcba54580..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/app.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion bootstrap -import { upgradeAdapter } from './upgrade_adapter'; - -// #enddocregion bootstrap - -declare var angular: any; - -angular.module('heroApp', []) - .controller('MainCtrl', function() { - this.message = 'Hello world'; - }); - -// #docregion bootstrap - -upgradeAdapter.bootstrap(document.body, ['heroApp'], {strictDi: true}); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts deleted file mode 100644 index 6ccaa31b9c..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -@NgModule({ - imports: [ BrowserModule ] -}) -export class AppModule {} - -angular.module('heroApp', []) - .controller('MainCtrl', function() { - this.message = 'Hello world'; - }); - -// #docregion -import { UpgradeAdapter } from '@angular/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(AppModule); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/app.module.ts deleted file mode 100644 index 5daeb671e3..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/app.module.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { UpgradeAdapter } from '@angular/upgrade'; - -import { MainController } from './main.controller'; -import { HeroDetailComponent } from './hero-detail.component'; - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ HeroDetailComponent ] -}) -export class AppModule {} - -declare var angular: any; -const upgradeAdapter = new UpgradeAdapter(AppModule); - -angular.module('heroApp', []) - .controller('MainController', MainController) - .directive('heroDetail', upgradeAdapter.downgradeNg2Component(HeroDetailComponent)); - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/app.module.ts deleted file mode 100644 index 7ae5fd331d..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/app.module.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { HeroDetailComponent } from './hero-detail.component'; -import { HeroesService } from './heroes.service'; -import { upgradeAdapter } from './upgrade_adapter'; - -declare var angular: any; - -// #docregion register -angular.module('heroApp', []) - .service('heroes', HeroesService) - .directive('heroDetail', - upgradeAdapter.downgradeNg2Component(HeroDetailComponent)); - -upgradeAdapter.upgradeNg1Provider('heroes'); - -// #enddocregion register - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/upgrade_adapter.ts deleted file mode 100644 index c98ab182a8..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/upgrade_adapter.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -import { HeroDetailComponent } from './hero-detail.component'; - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ HeroDetailComponent ] -}) -export class AppModule {} - -angular.module('heroApp', []) - .controller('MainCtrl', function() { - this.message = 'Hello world'; - }); - -// #docregion -import { UpgradeAdapter } from '@angular/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(AppModule); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/app.module.ts deleted file mode 100644 index 16b77819c5..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/app.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { heroDetailComponent } from './hero-detail.component'; -import { Heroes } from './heroes'; -import { upgradeAdapter } from './upgrade_adapter'; - -declare var angular: any; - -// #docregion register -angular.module('heroApp', []) - .factory('heroes', upgradeAdapter.downgradeNg2Provider(Heroes)) - .component('heroDetail', heroDetailComponent); -// #enddocregion register - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/upgrade_adapter.ts deleted file mode 100644 index d99d587f0f..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/upgrade_adapter.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -// #docregion ngmodule -import { Heroes } from './heroes'; - -@NgModule({ - imports: [ BrowserModule ], - providers: [ Heroes ] -}) -export class AppModule {} -// #enddocregion ngmodule -angular.module('heroApp', []) - .controller('MainCtrl', function() { - this.message = 'Hello world'; - }); - -// #docregion -import { UpgradeAdapter } from '@angular/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(AppModule); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/app.module.ts deleted file mode 100644 index 3484e0d797..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/app.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ContainerComponent } from './container.component'; -import { heroDetailComponent } from './hero-detail.component'; -import { upgradeAdapter } from './upgrade_adapter'; - -declare var angular: any; - -angular.module('heroApp', []) - .directive('myContainer', upgradeAdapter.downgradeNg2Component(ContainerComponent)) - .component('heroDetail', heroDetailComponent); - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/hero-detail.component.ts b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/hero-detail.component.ts deleted file mode 100644 index a8f842781d..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/hero-detail.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -// #docregion -export const heroDetailComponent = { - bindings: { - hero: '=' - }, - template: ` -

{{$ctrl.hero.name}}

-
- -
- ` -}; diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/upgrade_adapter.ts deleted file mode 100644 index b0f947c8e5..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/upgrade_adapter.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion -import { UpgradeAdapter } from '@angular/upgrade'; -import { NgModule, forwardRef } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -import { ContainerComponent } from './container.component'; - -export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); -const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ ContainerComponent, HeroDetail ] -}) -export class AppModule {} - -angular.module('heroApp', []) - .controller('MainCtrl', function() { - this.message = 'Hello world'; - }); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/app.module.ts deleted file mode 100644 index a09db040d1..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/app.module.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -import { MainController } from './main.controller'; -// #docregion downgradecomponent -import { HeroDetailComponent } from './hero-detail.component'; - -// #enddocregion downgradecomponent - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ HeroDetailComponent ] -}) -export class AppModule {} - -import { UpgradeAdapter } from '@angular/upgrade'; - -const upgradeAdapter = new UpgradeAdapter(AppModule); - -// #docregion downgradecomponent - -angular.module('heroApp', []) - .controller('MainController', MainController) - .directive('heroDetail', upgradeAdapter.downgradeNg2Component(HeroDetailComponent)); - -// #enddocregion downgradecomponent - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-static/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/downgrade-static/app.module.ts deleted file mode 100644 index d5f173b5b5..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-static/app.module.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -// #docregion downgradecomponent, ngmodule -import { HeroDetailComponent } from './hero-detail.component'; - -// #enddocregion downgradecomponent -@NgModule({ - imports: [ BrowserModule ], - declarations: [ HeroDetailComponent ] -}) -export class AppModule {} -// #enddocregion ngmodule -import { UpgradeAdapter } from '@angular/upgrade'; - -const upgradeAdapter = new UpgradeAdapter(AppModule); - -// #docregion downgradecomponent - -angular.module('heroApp', []) - .directive('heroDetail', upgradeAdapter.downgradeNg2Component(HeroDetailComponent)); - -// #enddocregion downgradecomponent - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/app.module.ts deleted file mode 100644 index 7e672c888c..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/app.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { heroDetail } from './hero-detail.component'; -import { ContainerComponent } from './container.component'; -import { upgradeAdapter } from './upgrade_adapter'; - - -declare var angular: any; - -angular.module('heroApp', []) - .component('heroDetail', heroDetail) - .directive('myContainer', upgradeAdapter.downgradeNg2Component(ContainerComponent)); - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/hero-detail.component.ts b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/hero-detail.component.ts deleted file mode 100644 index 175c1ed317..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/hero-detail.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -// #docregion -export const heroDetail = { - bindings: { - hero: '<', - deleted: '&' - }, - template: ` -

{{$ctrl.hero.name}} details!

-
{{$ctrl.hero.id}}
- - `, - controller: function() { - this.onDelete = () => { - this.deleted(this.hero); - }; - } -}; diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/upgrade_adapter.ts deleted file mode 100644 index b0f947c8e5..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/upgrade_adapter.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion -import { UpgradeAdapter } from '@angular/upgrade'; -import { NgModule, forwardRef } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -import { ContainerComponent } from './container.component'; - -export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); -const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ ContainerComponent, HeroDetail ] -}) -export class AppModule {} - -angular.module('heroApp', []) - .controller('MainCtrl', function() { - this.message = 'Hello world'; - }); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/app.module.ts b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/app.module.ts deleted file mode 100644 index 7e672c888c..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/app.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { heroDetail } from './hero-detail.component'; -import { ContainerComponent } from './container.component'; -import { upgradeAdapter } from './upgrade_adapter'; - - -declare var angular: any; - -angular.module('heroApp', []) - .component('heroDetail', heroDetail) - .directive('myContainer', upgradeAdapter.downgradeNg2Component(ContainerComponent)); - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/hero-detail.component.ts b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/hero-detail.component.ts deleted file mode 100644 index 862c904bbc..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/hero-detail.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -export const heroDetail = { - template: ` -

Windstorm details!

-
1
- `, - controller: function() { - } -}; diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/upgrade_adapter.ts b/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/upgrade_adapter.ts deleted file mode 100644 index c9173347bc..0000000000 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/upgrade_adapter.ts +++ /dev/null @@ -1,23 +0,0 @@ -// #docregion -import { UpgradeAdapter } from '@angular/upgrade'; -import { NgModule, forwardRef } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -import { ContainerComponent } from './container.component'; - -export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); - -// #docregion heroupgrade -const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ ContainerComponent, HeroDetail ] -}) -export class AppModule {} -// #enddocregion heroupgrade - -angular.module('heroApp', []) - .controller('MainCtrl', function() { - this.message = 'Hello world'; - }); diff --git a/public/docs/_examples/upgrade-adapter/e2e-spec.ts.disabled b/public/docs/_examples/upgrade-module/e2e-spec.ts similarity index 71% rename from public/docs/_examples/upgrade-adapter/e2e-spec.ts.disabled rename to public/docs/_examples/upgrade-module/e2e-spec.ts index 271224cccc..d7eefbbf1b 100644 --- a/public/docs/_examples/upgrade-adapter/e2e-spec.ts.disabled +++ b/public/docs/_examples/upgrade-module/e2e-spec.ts @@ -1,24 +1,18 @@ -'use strict'; // necessary for es6 output in node +'use strict'; // necessary for es6 output in node import { browser, element, by } from 'protractor'; +import { setProtractorToHybridMode } from '../protractor-helpers'; describe('Upgrade Tests', function () { - // Protractor doesn't support the UpgradeAdapter's asynchronous - // bootstrap with Angular 1 at the moment. Get around it by - // waiting for an element to get `ng-scope` class. - function waitForNg1AsyncBootstrap() { - browser.ignoreSynchronization = true; - browser.driver.wait(function() { - return element(by.css('.ng-scope')).isPresent(); - }, 5000); - } + beforeAll(function () { + setProtractorToHybridMode(); + }); describe('NG1 Auto-bootstrap', function() { beforeAll(function () { browser.get('/index-ng-app.html'); - setProtractorToNg1Mode(); }); it('bootstraps as expected', function () { @@ -31,7 +25,6 @@ describe('Upgrade Tests', function () { beforeAll(function () { browser.get('/index-bootstrap.html'); - setProtractorToNg1Mode(); }); it('bootstraps as expected', function () { @@ -44,20 +37,6 @@ describe('Upgrade Tests', function () { beforeAll(function () { browser.get('/index-1-2-hybrid-bootstrap.html'); - setProtractorToNg1Mode(); - }); - - it('bootstraps as expected', function () { - expect(element(by.css('#message')).getText()).toEqual('Hello world'); - }); - - }); - - describe('NG1-2 Hybrid Bootstrap with Shared UpgradeAdapter', function() { - - beforeAll(function () { - browser.get('/index-1-2-hybrid-shared-adapter-bootstrap.html'); - setProtractorToNg1Mode(); }); it('bootstraps as expected', function () { @@ -70,8 +49,6 @@ describe('Upgrade Tests', function () { beforeAll(function () { browser.get('/index-upgrade-static.html'); - setProtractorToNg1Mode(); - waitForNg1AsyncBootstrap(); }); it('renders', function () { @@ -85,8 +62,6 @@ describe('Upgrade Tests', function () { beforeAll(function () { browser.get('/index-upgrade-io.html'); - setProtractorToNg1Mode(); - waitForNg1AsyncBootstrap(); }); it('has inputs', function () { @@ -105,8 +80,6 @@ describe('Upgrade Tests', function () { beforeAll(function () { browser.get('/index-downgrade-static.html'); - setProtractorToNg1Mode(); - waitForNg1AsyncBootstrap(); }); it('renders', function () { @@ -119,15 +92,13 @@ describe('Upgrade Tests', function () { beforeAll(function () { browser.get('/index-downgrade-io.html'); - setProtractorToNg1Mode(); - waitForNg1AsyncBootstrap(); }); it('has inputs', function () { expect(element.all(by.css('h2')).first().getText()).toEqual('Windstorm details!'); }); - it('has outputs', function () { + xit('has outputs', function () { element.all(by.buttonText('Delete')).first().click(); expect(element.all(by.css('h2')).first().getText()).toEqual('Ex-Windstorm details!'); }); @@ -143,8 +114,6 @@ describe('Upgrade Tests', function () { beforeAll(function () { browser.get('/index-1-to-2-projection.html'); - setProtractorToNg1Mode(); - waitForNg1AsyncBootstrap(); }); it('can be transcluded into', function () { @@ -158,8 +127,6 @@ describe('Upgrade Tests', function () { beforeAll(function () { browser.get('/index-2-to-1-transclusion.html'); - setProtractorToNg1Mode(); - waitForNg1AsyncBootstrap(); }); it('can be projected into', function () { @@ -173,8 +140,6 @@ describe('Upgrade Tests', function () { beforeAll(function () { browser.get('/index-1-to-2-providers.html'); - setProtractorToNg1Mode(); - waitForNg1AsyncBootstrap(); }); it('works', function () { @@ -188,8 +153,6 @@ describe('Upgrade Tests', function () { beforeAll(function () { browser.get('/index-2-to-1-providers.html'); - setProtractorToNg1Mode(); - waitForNg1AsyncBootstrap(); }); it('works', function () { diff --git a/public/docs/_examples/upgrade-module/ts/app/1-2-hybrid-bootstrap/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/1-2-hybrid-bootstrap/app.module.ts new file mode 100644 index 0000000000..7a6b82cf92 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/1-2-hybrid-bootstrap/app.module.ts @@ -0,0 +1,29 @@ +declare var angular: angular.IAngularStatic; +// #docregion ngmodule +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; + +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion ngmodule +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); + +// #docregion bootstrap +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); +// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-bootstrap/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/1-bootstrap/app.module.ts similarity index 91% rename from public/docs/_examples/upgrade-adapter/ts/app/1-bootstrap/app.module.ts rename to public/docs/_examples/upgrade-module/ts/app/1-bootstrap/app.module.ts index 7b9d8c8dab..639b780d1b 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-bootstrap/app.module.ts +++ b/public/docs/_examples/upgrade-module/ts/app/1-bootstrap/app.module.ts @@ -1,5 +1,3 @@ -declare var angular: any; - angular.module('heroApp', []) .controller('MainCtrl', function() { this.message = 'Hello world'; diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-ng-app/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/1-ng-app/app.module.ts similarity index 80% rename from public/docs/_examples/upgrade-adapter/ts/app/1-ng-app/app.module.ts rename to public/docs/_examples/upgrade-module/ts/app/1-ng-app/app.module.ts index 37241e1a07..904f7578b8 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/1-ng-app/app.module.ts +++ b/public/docs/_examples/upgrade-module/ts/app/1-ng-app/app.module.ts @@ -1,5 +1,3 @@ -declare var angular: any; - angular.module('heroApp', []) .controller('MainCtrl', function() { this.message = 'Hello world'; diff --git a/public/docs/_examples/upgrade-module/ts/app/1-to-2-projection/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/1-to-2-projection/app.module.ts new file mode 100644 index 0000000000..080f80f0ef --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/1-to-2-projection/app.module.ts @@ -0,0 +1,36 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { MainController } from './main.controller'; +import { HeroDetailComponent } from './hero-detail.component'; + +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + HeroDetailComponent + ], + entryComponents: [ + HeroDetailComponent + ] +}) +export class AppModule { + ngDoBootstrap() {} +} + +angular.module('heroApp', []) + .controller('MainController', MainController) + .directive('heroDetail', downgradeComponent({ + component: HeroDetailComponent, + inputs: ['hero'] + }) as angular.IDirectiveFactory); + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/app/1-to-2-projection/hero-detail.component.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/hero-detail.component.ts rename to public/docs/_examples/upgrade-module/ts/app/1-to-2-projection/hero-detail.component.ts diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/main.controller.ts b/public/docs/_examples/upgrade-module/ts/app/1-to-2-projection/main.controller.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/1-to-2-projection/main.controller.ts rename to public/docs/_examples/upgrade-module/ts/app/1-to-2-projection/main.controller.ts diff --git a/public/docs/_examples/upgrade-module/ts/app/1-to-2-providers/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/1-to-2-providers/app.module.ts new file mode 100644 index 0000000000..5754494853 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/1-to-2-providers/app.module.ts @@ -0,0 +1,46 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroesService } from './heroes.service'; + +// #docregion register +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + providers: [{ + provide: 'heroes', + useFactory: (i: any) => i.get('heroes'), + deps: ['$injector'] + }], + // #enddocregion register + declarations: [ + HeroDetailComponent + ], + entryComponents: [ + HeroDetailComponent + ] +// #docregion register +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion register + +angular.module('heroApp', []) + .service('heroes', HeroesService) + .directive( + 'heroDetail', + downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory + ); + + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/app/1-to-2-providers/hero-detail.component.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/hero-detail.component.ts rename to public/docs/_examples/upgrade-module/ts/app/1-to-2-providers/hero-detail.component.ts diff --git a/public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/heroes.service.ts b/public/docs/_examples/upgrade-module/ts/app/1-to-2-providers/heroes.service.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/1-to-2-providers/heroes.service.ts rename to public/docs/_examples/upgrade-module/ts/app/1-to-2-providers/heroes.service.ts diff --git a/public/docs/_examples/upgrade-module/ts/app/2-to-1-providers/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/2-to-1-providers/app.module.ts new file mode 100644 index 0000000000..91235a1485 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/2-to-1-providers/app.module.ts @@ -0,0 +1,34 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; + +import { heroDetailComponent } from './hero-detail.component'; + +// #docregion ngmodule +import { Heroes } from './heroes'; + +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + providers: [ Heroes ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion ngmodule +// #docregion register +import { downgradeInjectable } from '@angular/upgrade/static'; + +angular.module('heroApp', []) + .factory('heroes', downgradeInjectable(Heroes)) + .component('heroDetail', heroDetailComponent); +// #enddocregion register + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/app/2-to-1-providers/hero-detail.component.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/hero-detail.component.ts rename to public/docs/_examples/upgrade-module/ts/app/2-to-1-providers/hero-detail.component.ts diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/heroes.ts b/public/docs/_examples/upgrade-module/ts/app/2-to-1-providers/heroes.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/2-to-1-providers/heroes.ts rename to public/docs/_examples/upgrade-module/ts/app/2-to-1-providers/heroes.ts diff --git a/public/docs/_examples/upgrade-module/ts/app/2-to-1-transclusion/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/2-to-1-transclusion/app.module.ts new file mode 100644 index 0000000000..599e711b5e --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/2-to-1-transclusion/app.module.ts @@ -0,0 +1,39 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { heroDetail, HeroDetailDirective } from './hero-detail.component'; +import { ContainerComponent } from './container.component'; + +// #docregion heroupgrade +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + ContainerComponent, + HeroDetailDirective + ], + entryComponents: [ + ContainerComponent + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion heroupgrade + +angular.module('heroApp', []) + .component('heroDetail', heroDetail) + .directive( + 'myContainer', + downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory + ); + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/container.component.ts b/public/docs/_examples/upgrade-module/ts/app/2-to-1-transclusion/container.component.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/2-to-1-transclusion/container.component.ts rename to public/docs/_examples/upgrade-module/ts/app/2-to-1-transclusion/container.component.ts diff --git a/public/docs/_examples/upgrade-module/ts/app/2-to-1-transclusion/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/app/2-to-1-transclusion/hero-detail.component.ts new file mode 100644 index 0000000000..a1bec385e0 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/2-to-1-transclusion/hero-detail.component.ts @@ -0,0 +1,28 @@ +// #docregion +export const heroDetail = { + bindings: { + hero: '=' + }, + template: ` +

{{$ctrl.hero.name}}

+
+ +
+ ` +}; +// #enddocregion + +import { Directive, ElementRef, Injector, Input } from '@angular/core'; +import { UpgradeComponent } from '@angular/upgrade/static'; +import { Hero } from '../hero'; + +@Directive({ + selector: 'hero-detail' +}) +export class HeroDetailDirective extends UpgradeComponent { + @Input() hero: Hero; + + constructor(elementRef: ElementRef, injector: Injector) { + super('heroDetail', elementRef, injector); + } +} diff --git a/public/docs/_examples/upgrade-module/ts/app/downgrade-io/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/downgrade-io/app.module.ts new file mode 100644 index 0000000000..1e836cfc9d --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/downgrade-io/app.module.ts @@ -0,0 +1,43 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { MainController } from './main.controller'; + +// #docregion downgradecomponent +import { HeroDetailComponent } from './hero-detail.component'; + +// #enddocregion downgradecomponent +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + HeroDetailComponent + ], + entryComponents: [ + HeroDetailComponent + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #docregion downgradecomponent + +angular.module('heroApp', []) + .controller('MainController', MainController) + .directive('heroDetail', downgradeComponent({ + component: HeroDetailComponent, + inputs: ['hero'], + outputs: ['deleted'] + }) as angular.IDirectiveFactory); + +// #enddocregion downgradecomponent + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/app/downgrade-io/hero-detail.component.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/hero-detail.component.ts rename to public/docs/_examples/upgrade-module/ts/app/downgrade-io/hero-detail.component.ts diff --git a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/main.controller.ts b/public/docs/_examples/upgrade-module/ts/app/downgrade-io/main.controller.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/downgrade-io/main.controller.ts rename to public/docs/_examples/upgrade-module/ts/app/downgrade-io/main.controller.ts diff --git a/public/docs/_examples/upgrade-module/ts/app/downgrade-static/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/downgrade-static/app.module.ts new file mode 100644 index 0000000000..4d621d2f03 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/downgrade-static/app.module.ts @@ -0,0 +1,42 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; + +// #docregion downgradecomponent, ngmodule +import { HeroDetailComponent } from './hero-detail.component'; + +// #enddocregion downgradecomponent +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + HeroDetailComponent + ], + entryComponents: [ + HeroDetailComponent + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion ngmodule +// #docregion downgradecomponent + +import { downgradeComponent } from '@angular/upgrade/static'; + +angular.module('heroApp', []) + .directive( + 'heroDetail', + downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory + ); + +// #enddocregion downgradecomponent + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-static/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/app/downgrade-static/hero-detail.component.ts similarity index 83% rename from public/docs/_examples/upgrade-adapter/ts/app/downgrade-static/hero-detail.component.ts rename to public/docs/_examples/upgrade-module/ts/app/downgrade-static/hero-detail.component.ts index cbcadfbd5a..df4a705f37 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/downgrade-static/hero-detail.component.ts +++ b/public/docs/_examples/upgrade-module/ts/app/downgrade-static/hero-detail.component.ts @@ -8,6 +8,4 @@ import { Component } from '@angular/core';
1
` }) -export class HeroDetailComponent { - -} +export class HeroDetailComponent { } diff --git a/public/docs/_examples/upgrade-adapter/ts/app/hero-detail.directive.ts b/public/docs/_examples/upgrade-module/ts/app/hero-detail.directive.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/hero-detail.directive.ts rename to public/docs/_examples/upgrade-module/ts/app/hero-detail.directive.ts diff --git a/public/docs/_examples/upgrade-adapter/ts/app/hero.ts b/public/docs/_examples/upgrade-module/ts/app/hero.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/hero.ts rename to public/docs/_examples/upgrade-module/ts/app/hero.ts diff --git a/public/docs/_examples/upgrade-module/ts/app/upgrade-io/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/upgrade-io/app.module.ts new file mode 100644 index 0000000000..599e711b5e --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/upgrade-io/app.module.ts @@ -0,0 +1,39 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { heroDetail, HeroDetailDirective } from './hero-detail.component'; +import { ContainerComponent } from './container.component'; + +// #docregion heroupgrade +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + ContainerComponent, + HeroDetailDirective + ], + entryComponents: [ + ContainerComponent + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion heroupgrade + +angular.module('heroApp', []) + .component('heroDetail', heroDetail) + .directive( + 'myContainer', + downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory + ); + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/container.component.ts b/public/docs/_examples/upgrade-module/ts/app/upgrade-io/container.component.ts similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/app/upgrade-io/container.component.ts rename to public/docs/_examples/upgrade-module/ts/app/upgrade-io/container.component.ts diff --git a/public/docs/_examples/upgrade-module/ts/app/upgrade-io/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/app/upgrade-io/hero-detail.component.ts new file mode 100644 index 0000000000..90c3273010 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/upgrade-io/hero-detail.component.ts @@ -0,0 +1,37 @@ +// #docregion +// #docregion hero-detail-io +export const heroDetail = { + bindings: { + hero: '<', + deleted: '&' + }, + template: ` +

{{$ctrl.hero.name}} details!

+
{{$ctrl.hero.id}}
+ + `, + controller: function() { + this.onDelete = () => { + this.deleted(this.hero); + }; + } +}; +// #enddocregion hero-detail-io + +// #docregion hero-detail-io-upgrade +import { Directive, ElementRef, Injector, Input, Output, EventEmitter } from '@angular/core'; +import { UpgradeComponent } from '@angular/upgrade/static'; +import { Hero } from '../hero'; + +@Directive({ + selector: 'hero-detail' +}) +export class HeroDetailDirective extends UpgradeComponent { + @Input() hero: Hero; + @Output() deleted: EventEmitter; + + constructor(elementRef: ElementRef, injector: Injector) { + super('heroDetail', elementRef, injector); + } +} +// #enddocregion hero-detail-io-upgrade diff --git a/public/docs/_examples/upgrade-module/ts/app/upgrade-static/app.module.ts b/public/docs/_examples/upgrade-module/ts/app/upgrade-static/app.module.ts new file mode 100644 index 0000000000..401963c35e --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/upgrade-static/app.module.ts @@ -0,0 +1,41 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { heroDetail, HeroDetailDirective } from './hero-detail.component'; +import { ContainerComponent } from './container.component'; + +// #docregion hero-detail-upgrade +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + HeroDetailDirective, + // #enddocregion hero-detail-upgrade + ContainerComponent + ], + entryComponents: [ + ContainerComponent + // #docregion hero-detail-upgrade + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion hero-detail-upgrade + +angular.module('heroApp', []) + .component('heroDetail', heroDetail) + .directive( + 'myContainer', + downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory + ); + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/container.component.ts b/public/docs/_examples/upgrade-module/ts/app/upgrade-static/container.component.ts similarity index 82% rename from public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/container.component.ts rename to public/docs/_examples/upgrade-module/ts/app/upgrade-static/container.component.ts index 1e3ebf509b..c28e5ea42d 100644 --- a/public/docs/_examples/upgrade-adapter/ts/app/upgrade-static/container.component.ts +++ b/public/docs/_examples/upgrade-module/ts/app/upgrade-static/container.component.ts @@ -8,6 +8,4 @@ import { Component } from '@angular/core'; ` }) -export class ContainerComponent { - -} +export class ContainerComponent { } diff --git a/public/docs/_examples/upgrade-module/ts/app/upgrade-static/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/app/upgrade-static/hero-detail.component.ts new file mode 100644 index 0000000000..02ddd293eb --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/app/upgrade-static/hero-detail.component.ts @@ -0,0 +1,25 @@ +// #docregion +// #docregion hero-detail +export const heroDetail = { + template: ` +

Windstorm details!

+
1
+ `, + controller: function() { + } +}; +// #enddocregion hero-detail + +// #docregion hero-detail-upgrade +import { Directive, ElementRef, Injector } from '@angular/core'; +import { UpgradeComponent } from '@angular/upgrade/static'; + +@Directive({ + selector: 'hero-detail' +}) +export class HeroDetailDirective extends UpgradeComponent { + constructor(elementRef: ElementRef, injector: Injector) { + super('heroDetail', elementRef, injector); + } +} +// #enddocregion hero-detail-upgrade diff --git a/public/docs/_examples/upgrade-adapter/ts/example-config.json b/public/docs/_examples/upgrade-module/ts/example-config.json similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/example-config.json rename to public/docs/_examples/upgrade-module/ts/example-config.json diff --git a/public/docs/_examples/upgrade-adapter/ts/index-1-2-hybrid-bootstrap.html b/public/docs/_examples/upgrade-module/ts/index-1-2-hybrid-bootstrap.html similarity index 95% rename from public/docs/_examples/upgrade-adapter/ts/index-1-2-hybrid-bootstrap.html rename to public/docs/_examples/upgrade-module/ts/index-1-2-hybrid-bootstrap.html index fc090c9eb9..593dafe854 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-1-2-hybrid-bootstrap.html +++ b/public/docs/_examples/upgrade-module/ts/index-1-2-hybrid-bootstrap.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/upgrade-adapter/ts/index-1-to-2-projection.html b/public/docs/_examples/upgrade-module/ts/index-1-to-2-projection.html similarity index 96% rename from public/docs/_examples/upgrade-adapter/ts/index-1-to-2-projection.html rename to public/docs/_examples/upgrade-module/ts/index-1-to-2-projection.html index ae3f8e8a31..a779fb57ba 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-1-to-2-projection.html +++ b/public/docs/_examples/upgrade-module/ts/index-1-to-2-projection.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/upgrade-adapter/ts/index-1-to-2-providers.html b/public/docs/_examples/upgrade-module/ts/index-1-to-2-providers.html similarity index 95% rename from public/docs/_examples/upgrade-adapter/ts/index-1-to-2-providers.html rename to public/docs/_examples/upgrade-module/ts/index-1-to-2-providers.html index af1c6f4b26..281a23aeec 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-1-to-2-providers.html +++ b/public/docs/_examples/upgrade-module/ts/index-1-to-2-providers.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/upgrade-adapter/ts/index-2-to-1-providers.html b/public/docs/_examples/upgrade-module/ts/index-2-to-1-providers.html similarity index 95% rename from public/docs/_examples/upgrade-adapter/ts/index-2-to-1-providers.html rename to public/docs/_examples/upgrade-module/ts/index-2-to-1-providers.html index 778cce946c..1652b9f397 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-2-to-1-providers.html +++ b/public/docs/_examples/upgrade-module/ts/index-2-to-1-providers.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/upgrade-adapter/ts/index-2-to-1-transclusion.html b/public/docs/_examples/upgrade-module/ts/index-2-to-1-transclusion.html similarity index 95% rename from public/docs/_examples/upgrade-adapter/ts/index-2-to-1-transclusion.html rename to public/docs/_examples/upgrade-module/ts/index-2-to-1-transclusion.html index 721284383c..a40579e3be 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-2-to-1-transclusion.html +++ b/public/docs/_examples/upgrade-module/ts/index-2-to-1-transclusion.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/upgrade-adapter/ts/index-bootstrap.html b/public/docs/_examples/upgrade-module/ts/index-bootstrap.html similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/index-bootstrap.html rename to public/docs/_examples/upgrade-module/ts/index-bootstrap.html diff --git a/public/docs/_examples/upgrade-adapter/ts/index-downgrade-io.html b/public/docs/_examples/upgrade-module/ts/index-downgrade-io.html similarity index 97% rename from public/docs/_examples/upgrade-adapter/ts/index-downgrade-io.html rename to public/docs/_examples/upgrade-module/ts/index-downgrade-io.html index 625c93fa35..5899dd12de 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-downgrade-io.html +++ b/public/docs/_examples/upgrade-module/ts/index-downgrade-io.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/upgrade-adapter/ts/index-downgrade-static.html b/public/docs/_examples/upgrade-module/ts/index-downgrade-static.html similarity index 95% rename from public/docs/_examples/upgrade-adapter/ts/index-downgrade-static.html rename to public/docs/_examples/upgrade-module/ts/index-downgrade-static.html index 01f920205c..44f2bfc829 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-downgrade-static.html +++ b/public/docs/_examples/upgrade-module/ts/index-downgrade-static.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/upgrade-adapter/ts/index-ng-app.html b/public/docs/_examples/upgrade-module/ts/index-ng-app.html similarity index 100% rename from public/docs/_examples/upgrade-adapter/ts/index-ng-app.html rename to public/docs/_examples/upgrade-module/ts/index-ng-app.html diff --git a/public/docs/_examples/upgrade-adapter/ts/index-upgrade-io.html b/public/docs/_examples/upgrade-module/ts/index-upgrade-io.html similarity index 95% rename from public/docs/_examples/upgrade-adapter/ts/index-upgrade-io.html rename to public/docs/_examples/upgrade-module/ts/index-upgrade-io.html index 9a74866eee..7e1570dcfa 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-upgrade-io.html +++ b/public/docs/_examples/upgrade-module/ts/index-upgrade-io.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/upgrade-adapter/ts/index-upgrade-static.html b/public/docs/_examples/upgrade-module/ts/index-upgrade-static.html similarity index 95% rename from public/docs/_examples/upgrade-adapter/ts/index-upgrade-static.html rename to public/docs/_examples/upgrade-module/ts/index-upgrade-static.html index 6354c9a5dd..6083cb52a2 100644 --- a/public/docs/_examples/upgrade-adapter/ts/index-upgrade-static.html +++ b/public/docs/_examples/upgrade-module/ts/index-upgrade-static.html @@ -8,7 +8,7 @@ - + diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/e2e-spec.ts.disabled b/public/docs/_examples/upgrade-phonecat-1-typescript/e2e-spec.ts similarity index 100% rename from public/docs/_examples/upgrade-phonecat-1-typescript/e2e-spec.ts.disabled rename to public/docs/_examples/upgrade-phonecat-1-typescript/e2e-spec.ts diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/e2e-spec.ts.disabled b/public/docs/_examples/upgrade-phonecat-2-hybrid/e2e-spec.ts similarity index 88% rename from public/docs/_examples/upgrade-phonecat-2-hybrid/e2e-spec.ts.disabled rename to public/docs/_examples/upgrade-phonecat-2-hybrid/e2e-spec.ts index 0e27367ec8..6dbf214ce8 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/e2e-spec.ts.disabled +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/e2e-spec.ts @@ -1,14 +1,15 @@ -'use strict'; // necessary for es6 output in node +'use strict'; // necessary for es6 output in node import { browser, element, by } from 'protractor'; +import { setProtractorToHybridMode } from '../protractor-helpers'; // Angular E2E Testing Guide: // https://docs.angularjs.org/guide/e2e-testing describe('PhoneCat Application', function() { - beforeAll(function() { - setProtractorToNg1Mode(); + beforeAll(function () { + setProtractorToHybridMode(); }); it('should redirect `index.html` to `index.html#!/phones', function() { @@ -16,7 +17,7 @@ describe('PhoneCat Application', function() { expect(browser.getLocationAbsUrl()).toBe('/phones'); }); - describe('View: Phone list', function() { + xdescribe('View: Phone list', function() { beforeEach(function() { browser.get('index.html#!/phones'); @@ -68,13 +69,13 @@ describe('PhoneCat Application', function() { query.sendKeys('nexus'); element.all(by.css('.phones li a')).first().click(); - browser.refresh(); // Not sure why this is needed but it is. The route change works fine. + browser.sleep(200); // Not sure why this is needed but it is. The route change works fine. expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s'); }); }); - describe('View: Phone detail', function() { + xdescribe('View: Phone detail', function() { beforeEach(function() { browser.get('index.html#!/phones/nexus-s'); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/.gitignore b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/.gitignore new file mode 100644 index 0000000000..316ea7d8ab --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/.gitignore @@ -0,0 +1,3 @@ +**/*.js +aot/**/*.ts +!rollup-config.js diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/aot-wip/bs-config.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/aot-wip/bs-config.json new file mode 100644 index 0000000000..7c85d6eddd --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/aot-wip/bs-config.json @@ -0,0 +1,5 @@ +{ + "port": 8000, + "files": ["./aot/**/*.{html,htm,css,js}"], + "server": { "baseDir": "./aot" } +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/aot-wip/index.html b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/aot-wip/index.html new file mode 100644 index 0000000000..14b9e6b6a9 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/aot-wip/index.html @@ -0,0 +1,36 @@ + + + + + + Angular Tour of Heroes + + + + + + + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.module.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.module.ts index 7b47c03950..9fc7fea21f 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.module.ts +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.module.ts @@ -3,6 +3,9 @@ import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; // #enddocregion bare +// #docregion upgrademodule +import { UpgradeModule } from '@angular/upgrade/static'; +// #enddocregion upgrademodule // #docregion httpmodule import { HttpModule } from '@angular/http'; // #enddocregion httpmodule @@ -22,18 +25,20 @@ import { PhoneListComponent } from './phone-list/phone-list.component'; import { PhoneDetailComponent } from './phone-detail/phone-detail.component'; // #enddocregion phonedetail -// #docregion bare, httpmodule, phone, phonelist, phonedetail, checkmarkpipe +// #docregion bare, upgrademodule, httpmodule, phone, phonelist, phonedetail, checkmarkpipe @NgModule({ imports: [ BrowserModule, // #enddocregion bare + UpgradeModule, + // #enddocregion upgrademodule HttpModule, // #enddocregion httpmodule, phone FormsModule, - // #docregion bare, httpmodule, phone + // #docregion bare, upgrademodule, httpmodule, phone ], - // #enddocregion bare, httpmodule, phone + // #enddocregion bare, upgrademodule, httpmodule, phone declarations: [ PhoneListComponent, // #enddocregion phonelist @@ -42,10 +47,35 @@ import { PhoneDetailComponent } from './phone-detail/phone-detail.component'; CheckmarkPipe // #docregion phonelist, phonedetail ], - // #docregion phone - providers: [ Phone ] -// #docregion bare, httpmodule, phonelist + entryComponents: [ + PhoneListComponent, + // #enddocregion phonelist + PhoneDetailComponent + // #enddocregion phonedetail + ], + // #docregion phone, routeparams + providers: [ + Phone, + // #enddocregion phone + { + provide: '$routeParams', + useFactory: routeParamsFactory, + deps: ['$injector'] + } + // #docregion phone + ] + // #enddocregion routeparams +// #docregion bare, upgrademodule, httpmodule, phone, phonelist }) -export class AppModule {} -// #enddocregion httpmodule, phone, phonelist, phonedetail, checkmarkpipe -// #enddocregion bare +export class AppModule { + // #enddocregion bare + ngDoBootstrap() {} + // #docregion bare +} +// #enddocregion bare, upgrademodule, httpmodule, phone, phonelist, phonedetail, checkmarkpipe + +// #docregion routeparams +export function routeParamsFactory(i: any) { + return i.get('$routeParams'); +} +// #enddocregion routeparams diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts index b19eea598d..c4673475fb 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts @@ -3,6 +3,11 @@ import { Injectable } from '@angular/core'; import { Http, Response } from '@angular/http'; import { Observable } from 'rxjs/Rx'; +// #docregion downgrade-injectable +declare var angular: angular.IAngularStatic; +import { downgradeInjectable } from '@angular/upgrade/static'; +// #enddocregion downgrade-injectable + import 'rxjs/add/operator/map'; // #docregion phonedata-interface @@ -14,10 +19,10 @@ export interface PhoneData { // #enddocregion phonedata-interface // #docregion fullclass -// #docregion classdef +// #docregion classdef, downgrade-injectable @Injectable() export class Phone { -// #enddocregion classdef +// #enddocregion classdef, downgrade-injectable constructor(private http: Http) { } query(): Observable { return this.http.get(`phones/phones.json`) @@ -27,7 +32,11 @@ export class Phone { return this.http.get(`phones/${id}.json`) .map((res: Response) => res.json()); } -// #docregion classdef +// #docregion classdef, downgrade-injectable } // #enddocregion classdef // #enddocregion fullclass + +angular.module('core.phone') + .factory('phone', downgradeInjectable(Phone)); +// #enddocregion downgrade-injectable diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main-aot.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main-aot.ts new file mode 100644 index 0000000000..e43d57a538 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main-aot.ts @@ -0,0 +1,11 @@ +// #docregion bootstrap +import { platformBrowser } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; + +import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory'; + +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.documentElement, ['phonecatApp']); +}); +// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main.ts index 06c61fd0d4..886e8ffac8 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main.ts +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main.ts @@ -1,51 +1,11 @@ -// #docregion import-adapter -import { UpgradeAdapter } from '@angular/upgrade'; -declare var angular: any; +// #docregion bootstrap +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { UpgradeModule } from '@angular/upgrade/static'; import { AppModule } from './app.module'; -// #enddocregion import-adapter -// #docregion phone-service -import { Phone } from './core/phone/phone.service'; -// #enddocregion phone-service -// #docregion phone-list -import { PhoneListComponent } from './phone-list/phone-list.component'; - -// #enddocregion phone-list -// #docregion phone-detail -import { PhoneDetailComponent } from './phone-detail/phone-detail.component'; - -// #enddocregion phone-detail -// #docregion init-adapter -let upgradeAdapter = new UpgradeAdapter(AppModule); -// #enddocregion init-adapter - -// #docregion routeparams -upgradeAdapter.upgradeNg1Provider('$routeParams'); -// #enddocregion routeparams - -// #docregion phone-service - -angular.module('core.phone') - .factory('phone', upgradeAdapter.downgradeNg2Provider(Phone)); -// #enddocregion phone-service -// #docregion phone-list - -angular.module('phoneList') - .directive( - 'phoneList', - upgradeAdapter.downgradeNg2Component(PhoneListComponent) as angular.IDirectiveFactory - ); -// #enddocregion phone-list -// #docregion phone-detail - -angular.module('phoneDetail') - .directive( - 'phoneDetail', - upgradeAdapter.downgradeNg2Component(PhoneDetailComponent) as angular.IDirectiveFactory - ); -// #enddocregion phone-detail - -// #docregion bootstrap -upgradeAdapter.bootstrap(document.documentElement, ['phonecatApp']); +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.documentElement, ['phonecatApp']); +}); // #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ng1.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ng1.ts index 333c08aa45..80282858c4 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ng1.ts +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ng1.ts @@ -1,6 +1,6 @@ // #docregion +declare var angular: angular.IAngularStatic; import { Phone, PhoneData } from '../core/phone/phone.service'; -declare var angular: any; class PhoneDetailController { phone: PhoneData; diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts index e44cd42997..98f05ca599 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts @@ -1,4 +1,8 @@ // #docplaster +// #docregion +declare var angular: angular.IAngularStatic; +import { downgradeComponent } from '@angular/upgrade/static'; + // #docregion initialclass import { Component, Inject } from '@angular/core'; @@ -19,9 +23,7 @@ export class PhoneDetailComponent { phone: PhoneData; mainImageUrl: string; - constructor(@Inject('$routeParams') - $routeParams: angular.route.IRouteParamsService, - phone: Phone) { + constructor(@Inject('$routeParams') $routeParams: any, phone: Phone) { phone.get($routeParams['phoneId']).subscribe(phone => { this.phone = phone; this.setImage(phone.images[0]); @@ -33,3 +35,9 @@ export class PhoneDetailComponent { } } // #enddocregion initialclass + +angular.module('phoneDetail') + .directive( + 'phoneDetail', + downgradeComponent({component: PhoneDetailComponent}) as angular.IDirectiveFactory + ); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ng1.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ng1.ts index 47b1e35e4a..81eac1cd81 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ng1.ts +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ng1.ts @@ -1,6 +1,6 @@ // #docregion +declare var angular: angular.IAngularStatic; import { Phone, PhoneData } from '../core/phone/phone.service'; -declare var angular: any; class PhoneListController { phones: PhoneData[]; diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts index 4a957e0471..bdd5930b79 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts @@ -1,14 +1,21 @@ -// #docplaster +// #docregion downgrade-component +declare var angular: angular.IAngularStatic; +import { downgradeComponent } from '@angular/upgrade/static'; + +// #enddocregion downgrade-component + // #docregion initialclass import { Component } from '@angular/core'; import { Phone, PhoneData } from '../core/phone/phone.service'; +// #docregion downgrade-component @Component({ moduleId: module.id, selector: 'phone-list', templateUrl: 'phone-list.template.html' }) export class PhoneListComponent { + // #enddocregion downgrade-component phones: PhoneData[]; query: string; orderProp: string; @@ -54,6 +61,13 @@ export class PhoneListComponent { return phones; } // #enddocregion getphones - // #docregion initialclass + // #docregion initialclass, downgrade-component } // #enddocregion initialclass + +angular.module('phoneList') + .directive( + 'phoneList', + downgradeComponent({component: PhoneListComponent}) as angular.IDirectiveFactory + ); +// #enddocregion downgrade-component diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/rollup-config.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/rollup-config.js new file mode 100644 index 0000000000..aeb227689c --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/rollup-config.js @@ -0,0 +1,21 @@ +// #docregion +import rollup from 'rollup' +import nodeResolve from 'rollup-plugin-node-resolve' +import commonjs from 'rollup-plugin-commonjs'; +import uglify from 'rollup-plugin-uglify' + +//paths are relative to the execution path +export default { + entry: 'app/main-aot.js', + dest: 'aot/dist/build.js', // output a single application bundle + sourceMap: true, + sourceMapFile: 'aot/dist/build.js.map', + format: 'iife', + plugins: [ + nodeResolve({jsnext: true, module: true}), + commonjs({ + include: ['node_modules/rxjs/**'] + }), + uglify() + ] +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js index 18b947dbb5..afb510f0a1 100644 --- a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js @@ -20,8 +20,10 @@ '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'npm:@angular/http/bundles/http.umd.js', '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', // other libraries 'rxjs': 'npm:rxjs', diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/tsconfig-aot.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/tsconfig-aot.json new file mode 100644 index 0000000000..97d6f592a0 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/tsconfig-aot.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + + "files": [ + "app/app.module.ts", + "app/main-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "skipMetadataEmit" : true + } +} diff --git a/public/docs/_examples/upgrade-phonecat-3-final/e2e-spec.ts b/public/docs/_examples/upgrade-phonecat-3-final/e2e-spec.ts index 49f0ca75a9..6f47c54d02 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/e2e-spec.ts +++ b/public/docs/_examples/upgrade-phonecat-3-final/e2e-spec.ts @@ -1,4 +1,4 @@ -'use strict'; // necessary for es6 output in node +'use strict'; // necessary for es6 output in node import { browser, element, by } from 'protractor'; @@ -67,11 +67,7 @@ describe('PhoneCat Application', function() { // #docregion links it('should render phone specific links', function() { let query = element(by.css('input')); - // https://github.com/angular/protractor/issues/2019 - let str = 'nexus'; - for (let i = 0; i < str.length; i++) { - query.sendKeys(str.charAt(i)); - } + query.sendKeys('nexus'); element.all(by.css('.phones li a')).first().click(); browser.getCurrentUrl().then(function(url: string) { expect(url.endsWith('/phones/nexus-s')).toBe(true); diff --git a/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js b/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js index 592029cd65..3c341b38e5 100644 --- a/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js +++ b/public/docs/_examples/upgrade-phonecat-3-final/ts/systemjs.config.1.js @@ -20,8 +20,10 @@ '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'npm:@angular/http/bundles/http.umd.js', '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', // other libraries 'rxjs': 'npm:rxjs', diff --git a/public/docs/_examples/user-input/dart/pubspec.yaml b/public/docs/_examples/user-input/dart/pubspec.yaml index 07a934d480..d1de0bf878 100644 --- a/public/docs/_examples/user-input/dart/pubspec.yaml +++ b/public/docs/_examples/user-input/dart/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: '>=1.19.0 <2.0.0' dependencies: angular2: ^2.0.0 +dev_dependencies: browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/user-input/ts/index.html b/public/docs/_examples/user-input/ts/index.html index f72530d64f..8cc2f5a880 100644 --- a/public/docs/_examples/user-input/ts/index.html +++ b/public/docs/_examples/user-input/ts/index.html @@ -7,7 +7,7 @@ - + diff --git a/public/docs/_examples/webpack/ts/package.webpack.json b/public/docs/_examples/webpack/ts/package.webpack.json index ed36c0f33f..553ca9338a 100644 --- a/public/docs/_examples/webpack/ts/package.webpack.json +++ b/public/docs/_examples/webpack/ts/package.webpack.json @@ -14,14 +14,14 @@ } ], "dependencies": { - "@angular/common": "~2.1.1", - "@angular/compiler": "~2.1.1", - "@angular/core": "~2.1.1", - "@angular/forms": "~2.1.1", - "@angular/http": "~2.1.1", - "@angular/platform-browser": "~2.1.1", - "@angular/platform-browser-dynamic": "~2.1.1", - "@angular/router": "~3.1.1", + "@angular/common": "~2.2.0", + "@angular/compiler": "~2.2.0", + "@angular/core": "~2.2.0", + "@angular/forms": "~2.2.0", + "@angular/http": "~2.2.0", + "@angular/platform-browser": "~2.2.0", + "@angular/platform-browser-dynamic": "~2.2.0", + "@angular/router": "~3.2.0", "core-js": "^2.4.1", "rxjs": "5.0.0-beta.12", "zone.js": "^0.6.25" diff --git a/public/docs/_layout.jade b/public/docs/_layout.jade index b1f38cc12a..a59a28af1d 100644 --- a/public/docs/_layout.jade +++ b/public/docs/_layout.jade @@ -1,5 +1,22 @@ //- WARNING: _layout.jade and _layout-dart-api.jade should match in terms of content //- except that one uses Harp partial/yield and the other uses Jade extends/include. + +- function tsApiHrefToDart(match, hrefApi, dontcare1, urlRest) { +- // Simple argument values: +- // hrefApi: href="../api/ +- // urlRest: core/index/ViewChild-var.html" +- // console.log(`got match on ${match}, 1: ${hrefApi}, 3: ${urlRest}`); +- var matches = urlRest.match(/^(\w*)\/index\/(\w*)-(\w*)(\.html")$/); +- // console.log(`urlRest matches ${matches}`); +- if (!matches) return match; // leave unchanged +- var i = 1; // matches[0] corresponds to the fully matched result +- var libName = matches[i++]; +- var apiPageEntryName = matches[i++]; +- var apiEntryKind = matches[i++]; +- var suffix = matches[i++]; +- return hrefApi + 'angular2.' + libName + '/' + apiPageEntryName + '-class' + suffix; +- } + if jade2ng .side-nav--offset != partial("../_includes/_hero") @@ -35,8 +52,10 @@ else article(class="l-content-small grid-fluid docs-content") != yield else + - var isDart = current.path[1] === 'dart'; + - var regex = /(href=\"(\.?\.\/)*api\/)(.*")/g; article(class="l-content-small grid-fluid docs-content") - != yield + != !isDart ? yield : yield.replace(regex, tsApiHrefToDart) if (current.path[3] == 'guide' || current.path[3] == 'tutorial') && current.path[4] != partial("../_includes/_next-item") diff --git a/public/docs/dart/latest/_quickstart_repo.jade b/public/docs/dart/latest/_quickstart_repo.jade deleted file mode 100644 index e72fbfacf2..0000000000 --- a/public/docs/dart/latest/_quickstart_repo.jade +++ /dev/null @@ -1,4 +0,0 @@ -.l-sub-section - :marked - Alternatively, begin with a - [download of the QuickStart source](https://github.com/angular-examples/quickstart/archive/master.zip). diff --git a/public/docs/dart/latest/_util-fns.jade b/public/docs/dart/latest/_util-fns.jade index 741d5b0c99..86925a3fa4 100644 --- a/public/docs/dart/latest/_util-fns.jade +++ b/public/docs/dart/latest/_util-fns.jade @@ -19,12 +19,17 @@ include ../../../_includes/_util-fns - var _appDir = 'lib'; - var _indexHtmlDir = 'web'; - var _mainDir = 'web'; +- var _ngRepoURL = 'https://github.com/dart-lang/angular2'; +//- Don't override this value quite yet: +//- var _ngDocRepoURL = 'https://github.com/dart-lang/site-webdev'; +- var _qsRepo = 'https://github.com/angular-examples/quickstart/archive/master.zip' //- NgModule related - var _AppModuleVsAppComp = 'AppComponent' - var _appModuleTsVsAppCompTs = 'app/app_component.dart' - var _appModuleTsVsMainTs = 'web/main.dart' - var _bootstrapModule = 'bootstrap' +- var _declsVsDirectives = 'directives' - var _moduleVsComp = 'component' - var _moduleVsRootComp = 'root component' - var _platformBrowserDynamicVsBootStrap = 'bootstrap' diff --git a/public/docs/dart/latest/api/index.jade b/public/docs/dart/latest/api/index.jade index 477cf84fb3..cdf4db0b3b 100644 --- a/public/docs/dart/latest/api/index.jade +++ b/public/docs/dart/latest/api/index.jade @@ -1,9 +1,12 @@ -:marked - > **Known issues:** The angular.io issue tracker contains [all known - issues][api-issues]; if you notice others, please [report - them][new-issue]. Thanks! +include ../_util-fns - [new-issue]: https://github.com/angular/angular.io/issues/new?labels=dart,api&title=%5BDart%5D%5BAPI%5D%20 - [api-issues]: https://github.com/angular/angular.io/issues?q=label%3Aapi+label%3Adart +:marked + > **Known issues:** The Angular issue tracker contains + [all known issues][api-issues]; if you notice others, please + [report them][new-issue]. Thanks! + + [new-issue]: !{_ngRepoURL}/issues/new?title=%5BAPI%20docs%5D + [api-issues]: !{_ngRepoURL}/issues +//- ?q=label%3Aapi api-list(src="api-list.json" lang="dart") diff --git a/public/docs/dart/latest/cheatsheet.jade b/public/docs/dart/latest/cheatsheet.jade index eec36cfb3f..8bad00b1ca 100644 --- a/public/docs/dart/latest/cheatsheet.jade +++ b/public/docs/dart/latest/cheatsheet.jade @@ -1,4 +1,4 @@ - var base = current.path[4] ? '.' : './guide'; -.l-content-small.grid-fluid.docs-content.cheatsheet +.l-content-small.docs-content.cheatsheet ngio-cheatsheet(src= base + '/cheatsheet.json') diff --git a/public/docs/dart/latest/cookbook/_data.json b/public/docs/dart/latest/cookbook/_data.json index a747acd83f..eb1a46ace4 100644 --- a/public/docs/dart/latest/cookbook/_data.json +++ b/public/docs/dart/latest/cookbook/_data.json @@ -60,7 +60,7 @@ "ts-to-js": { "title": "TypeScript to JavaScript", - "intro": "Convert Angular TypeScript examples into ES5 JavaScript", + "intro": "Convert Angular TypeScript examples into ES6 and ES5 JavaScript", "hide": true }, diff --git a/public/docs/dart/latest/glossary.jade b/public/docs/dart/latest/glossary.jade index 26feb4d9f3..6d0e7cb136 100644 --- a/public/docs/dart/latest/glossary.jade +++ b/public/docs/dart/latest/glossary.jade @@ -56,7 +56,7 @@ block routing-component-defn block append snake-case-defn :marked Library and file names are often spelled in snake_case. Examples include: - `angular2_tour_of_heroes` and `app_component.dart`. + `angular_tour_of_heroes` and `app_component.dart`. block zone-defn :marked diff --git a/public/docs/dart/latest/guide/architecture.jade b/public/docs/dart/latest/guide/architecture.jade index c72080b6e9..323f1aff6d 100644 --- a/public/docs/dart/latest/guide/architecture.jade +++ b/public/docs/dart/latest/guide/architecture.jade @@ -11,7 +11,7 @@ block includes block angular-parts :marked - Angular 2 for Dart is published as the `angular2` package, which + Angular for Dart is published as the `angular2` package, which (like many other Dart packages) is available via the Pub tool. block modules-in-dart diff --git a/public/docs/dart/latest/guide/component-styles.jade b/public/docs/dart/latest/guide/component-styles.jade index a101402e74..c1608c5b63 100644 --- a/public/docs/dart/latest/guide/component-styles.jade +++ b/public/docs/dart/latest/guide/component-styles.jade @@ -31,6 +31,6 @@ block module-id :marked Note that special measures must be taken in Angular2 for TypeScript, if relative URLs are to have the same interpretation. See - [here](../../../ts/latest/guide/component-styles.html#!#relative-urls) + [here](../../../ts/latest/guide/component-styles.html#relative-urls) for details. diff --git a/public/docs/dart/latest/guide/dependency-injection.jade b/public/docs/dart/latest/guide/dependency-injection.jade index 6656739107..fb6313e574 100644 --- a/public/docs/dart/latest/guide/dependency-injection.jade +++ b/public/docs/dart/latest/guide/dependency-injection.jade @@ -11,7 +11,7 @@ block ctor-syntax initializing properties simultaneously. block injectable-not-always-needed-in-ts - //- The [Angular 2 Dart Transformer](https://github.com/angular/angular/wiki/Angular-2-Dart-Transformer) + //- The [Angular Dart Transformer](https://github.com/angular/angular/wiki/Angular-2-Dart-Transformer) //- generates static code to replace the use of dart:mirrors. It requires that types be //- identified as targets for static code generation. Generally this is achieved //- by marking the class as @Injectable (though there are other mechanisms). diff --git a/public/docs/dart/latest/guide/displaying-data.jade b/public/docs/dart/latest/guide/displaying-data.jade index 5a9a1cdffb..d3c588076b 100644 --- a/public/docs/dart/latest/guide/displaying-data.jade +++ b/public/docs/dart/latest/guide/displaying-data.jade @@ -5,10 +5,6 @@ block includes - var _iterableUrl = 'https://api.dartlang.org/stable/dart-core/Iterable-class.html'; - var _boolean = 'boolean'; -block quickstart-repo - //- Must have this block so that Jade picks up the Dart include. - include ../_quickstart_repo - block hero-class :marked We've defined a class with a constructor, two properties (`id` and `name`), diff --git a/public/docs/dart/latest/guide/forms.jade b/public/docs/dart/latest/guide/forms.jade index f122411f16..a2d1feb8fa 100644 --- a/public/docs/dart/latest/guide/forms.jade +++ b/public/docs/dart/latest/guide/forms.jade @@ -96,12 +96,6 @@ figure.image-display +makeTabs('forms/dart/pubspec.yaml, forms/dart/web/index.html, forms/dart/web/main.dart', ',initial,', 'pubspec.yaml, web/index.html, web/main.dart') -.l-sub-section - :marked - Note the `platform_directives` entry in `pubspec.yaml`. - It imports core directives and, more importantly for this chapter, - **form directives**. - :marked So that the code can run, let's create a stub for the `` component. diff --git a/public/docs/dart/latest/guide/glossary.jade b/public/docs/dart/latest/guide/glossary.jade index 1d2eb49664..ff49e787f0 100644 --- a/public/docs/dart/latest/guide/glossary.jade +++ b/public/docs/dart/latest/guide/glossary.jade @@ -1,4 +1,4 @@ extends ../glossary -block var-def +block includes include ../_util-fns diff --git a/public/docs/dart/latest/guide/i18n.jade b/public/docs/dart/latest/guide/i18n.jade deleted file mode 100644 index 6778b6af28..0000000000 --- a/public/docs/dart/latest/guide/i18n.jade +++ /dev/null @@ -1 +0,0 @@ -!= partial("../../../_includes/_ts-temp") diff --git a/public/docs/dart/latest/guide/index.jade b/public/docs/dart/latest/guide/index.jade index 417bf9ea8d..7173f74d79 100644 --- a/public/docs/dart/latest/guide/index.jade +++ b/public/docs/dart/latest/guide/index.jade @@ -1,13 +1,4 @@ -extends ../../../ts/latest/guide/index.jade +extends ../../../ts/_cache/guide/index.jade block includes include ../_util-fns - -block example-links - :marked - Look for a link to that sample near the top of each page. - For example, the sample repo https://github.com/angular-examples/architecture - contains the code - for the [Architecture](architecture.html) chapter's sample. - A running version of that sample is at - https://angular-examples.github.io/architecture/. diff --git a/public/docs/dart/latest/guide/server-communication.jade b/public/docs/dart/latest/guide/server-communication.jade index 5dd2f5bace..e4b7b01c99 100644 --- a/public/docs/dart/latest/guide/server-communication.jade +++ b/public/docs/dart/latest/guide/server-communication.jade @@ -15,7 +15,7 @@ block demos-list block http-providers :marked Actually, it is unnecessary to include `BrowserClient` in the list of providers. - ***But*** as is mentioned in the *Angular 2 Dart Transformer* [wiki page][ng2dtri], + ***But*** as is mentioned in the *Angular Dart Transformer* [wiki page][ng2dtri], the template compiler _generates_ dependency injection code, hence all the identifiers used in DI have to be collected by the Angular transformer so that the libraries containing these identifiers can be transformed. diff --git a/public/docs/dart/latest/guide/template-syntax.jade b/public/docs/dart/latest/guide/template-syntax.jade index bee8fc97a7..fe62bd9084 100644 --- a/public/docs/dart/latest/guide/template-syntax.jade +++ b/public/docs/dart/latest/guide/template-syntax.jade @@ -48,16 +48,6 @@ block dart-type-exception-example In checked mode, the code above will result in a type exception: `String` isn't a subtype of `Hero`. -block dart-class-binding-bug - .callout.is-helpful - header Angular Issue #6901 - :marked - Issue [#6901][6901] prevents us from using `[class]`. As is illustrated - above, in the meantime we can achieve the same effect by binding to - `className`. - - [6901]: http://github.com/angular/angular/issues/6901 - block style-property-name-dart-diff .callout.is-helpful header Dart difference: Style property names diff --git a/public/docs/dart/latest/quickstart.jade b/public/docs/dart/latest/quickstart.jade index 50e3d516ab..838a02f45e 100644 --- a/public/docs/dart/latest/quickstart.jade +++ b/public/docs/dart/latest/quickstart.jade @@ -7,7 +7,6 @@ block includes - var _angular_browser_uri = 'angular2/platform/browser.dart' - var _angular_core_uri = 'angular2/core.dart' - var _stepInit = 3 - - var _quickstartSrcURL='https://github.com/angular-examples/quickstart' block setup-tooling :marked @@ -41,8 +40,11 @@ block install-packages packages (along with the packages they depend on). code-example(language="sh" class="code-shell"). - > pub get - Resolving dependencies... + pub get + +block create-your-app + :marked + Let's create a folder to hold our application and add a super-simple Angular component. block annotation-fields :marked @@ -57,6 +59,10 @@ block create-main li a #[b folder named #[code web]] li a file named #[code #[+adjExPath('app/main.ts')]] with the following content: +block commentary-on-index-html + :marked + Note the `` tag in the ``, this is *where your app lives!* + block run-app p. We have a few options for running our app. @@ -76,83 +82,85 @@ block run-app Once the app is running, the browser window should show the following: block build-app - .alert.is-important - :marked - If you don't see **My First Angular App**, make sure you've entered all the code correctly, - in the [proper folders](#wrap-up), - and run `pub get`. - - .l-verbose-section#section-angular-run-app - :marked - ### Building the app (generating JavaScript) - - Before deploying the app, we need to generate JavaScript files. - The `pub build` command makes that easy. - - code-example(language="sh" class="code-shell"). - > pub build - Loading source assets... - - :marked - The generated JavaScript appears, along with supporting files, - under a directory named `build`. - - #angular_transformer - h4 Using the Angular transformer - - p. - When generating JavaScript for an Angular app, - be sure to use the Angular transformer. - It analyzes the Dart code, - converting reflection-using code to static code - that Dart's build tools can compile to faster, smaller JavaScript. - The highlighted lines in pubspec.yaml - configure the Angular transformer: - - - var stylePattern = { otl: /(transformers:)|(- angular2:)|(entry_points.*$)/gm }; - +makeExample('quickstart/dart/pubspec.yaml', null, 'pubspec.yaml', stylePattern) - - p. - The entry_points item - identifies the Dart file in our app - that has a main() function. - For more information, see the -
Angular - transformer wiki page. - - .l-sub-section#performance - h3 Performance, the transformer, and Angular 2 libraries - p. - When an app imports bootstrap.dart, - it also gets dart:mirrors, - a reflection library that - causes performance problems when compiled to JavaScript. - Don't worry, - the Angular transformer converts the app's entry points - (entry_points in pubspec.yaml) - so that they don't use mirrors. - - #dart_to_js_script_rewriter - h4 Using dart_to_js_script_rewriter - - :marked - To improve the app's performance, convert the - HTML file to directly include the generated JavaScript; - one way to do that is with `dart_to_js_script_rewriter`. - To use the rewriter, specify `dart_to_js_script_rewriter` in both - the `dependencies` and `transformers` sections of the pubspec. - - - var stylePattern = { otl: /(dart_to_js_script_rewriter.*$)|(- dart_to_js_script_rewriter.*$)|(dependencies:)|(transformers:)/gm }; - +makeExample('quickstart/dart/pubspec.yaml', null, 'pubspec.yaml', stylePattern) - + //- Remove details of building from QS for now. (It is too early for these details.) + if false .alert.is-important :marked - The `dart_to_js_script_rewriter` transformer must be - **after** the `angular2` transformer in `pubspec.yaml`. + If you don't see **Hello Angular!**, make sure you've entered all the code correctly, + in the [proper folders](#wrap-up), + and run `pub get`. - :marked - For more information, see the docs for - [dart_to_js_script_rewriter](https://pub.dartlang.org/packages/dart_to_js_script_rewriter). + .l-verbose-section#section-angular-run-app + :marked + ### Building the app (generating JavaScript) + + Before deploying the app, we need to generate JavaScript files. + The `pub build` command makes that easy. + + code-example(language="sh" class="code-shell"). + > pub build + Loading source assets... + + :marked + The generated JavaScript appears, along with supporting files, + under a directory named `build`. + + #angular_transformer + h4 Using the Angular transformer + + p. + When generating JavaScript for an Angular app, + be sure to use the Angular transformer. + It analyzes the Dart code, + converting reflection-using code to static code + that Dart's build tools can compile to faster, smaller JavaScript. + The highlighted lines in pubspec.yaml + configure the Angular transformer: + + - var stylePattern = { otl: /(transformers:)|(- angular2:)|(entry_points.*$)/gm }; + +makeExample('quickstart/dart/pubspec.yaml', null, 'pubspec.yaml', stylePattern) + + p. + The entry_points item + identifies the Dart file in our app + that has a main() function. + For more information, see the + Angular + transformer wiki page. + + .l-sub-section#performance + h3 Performance, the transformer, and Angular libraries + p. + When an app imports bootstrap.dart, + it also gets dart:mirrors, + a reflection library that + causes performance problems when compiled to JavaScript. + Don't worry, + the Angular transformer converts the app's entry points + (entry_points in pubspec.yaml) + so that they don't use mirrors. + + #dart_to_js_script_rewriter + h4 Using dart_to_js_script_rewriter + + :marked + To improve the app's performance, convert the + HTML file to directly include the generated JavaScript; + one way to do that is with `dart_to_js_script_rewriter`. + To use the rewriter, specify `dart_to_js_script_rewriter` in both + the `dependencies` and `transformers` sections of the pubspec. + + - var stylePattern = { otl: /(dart_to_js_script_rewriter.*$)|(- dart_to_js_script_rewriter.*$)|(dependencies:)|(transformers:)/gm }; + +makeExample('quickstart/dart/pubspec.yaml', null, 'pubspec.yaml', stylePattern) + + .alert.is-important + :marked + The `dart_to_js_script_rewriter` transformer must be + **after** the `angular2` transformer in `pubspec.yaml`. + + :marked + For more information, see the docs for + [dart_to_js_script_rewriter](https://pub.dartlang.org/packages/dart_to_js_script_rewriter). block server-watching :marked @@ -160,11 +168,11 @@ block server-watching .alert.is-important :marked - Be sure to terminate the `pub serve` process once you stop working on this app. + Be sure to terminate your local server once you stop working on this app. block project-file-structure .filetree - .file angular2_quickstart + .file angular_quickstart .children .file lib .children diff --git a/public/docs/dart/latest/resources.jade b/public/docs/dart/latest/resources.jade index 39f148b57f..f65bc343aa 100644 --- a/public/docs/dart/latest/resources.jade +++ b/public/docs/dart/latest/resources.jade @@ -1,4 +1,4 @@ -// TODO: don't duplicate text from /docs/js/latest/resources.jade +// TODO: don't duplicate text from /docs/ts/latest/resources.jade .l-main-section h2 Victor Savkin's Blog Posts ul @@ -12,7 +12,7 @@ .l-main-section h2 Videos - h4 Intro Vidoes + h4 Intro Videos ul li Building a Todo App by David East li Angular 2 Forms by David East @@ -33,7 +33,6 @@ .l-main-section h2 API Design Docs & Notes ul - li Best Practices li Best Practices li API Design Docs li Meeting Notes diff --git a/public/docs/dart/latest/tutorial/toh-pt1.jade b/public/docs/dart/latest/tutorial/toh-pt1.jade index 218d35c788..e04a4f1bef 100644 --- a/public/docs/dart/latest/tutorial/toh-pt1.jade +++ b/public/docs/dart/latest/tutorial/toh-pt1.jade @@ -1,8 +1,6 @@ include ../_util-fns :marked - # Once Upon a Time - Every story starts somewhere. Our story starts where the [QuickStart](../quickstart.html) ends. :marked @@ -13,11 +11,11 @@ include ../_util-fns TODO: Recommend stagehand? --> - Copy the "QuickStart" code to a new folder and rename the folder `angular2_tour_of_heroes`. + Copy the "QuickStart" code to a new folder and rename the folder `angular_tour_of_heroes`. We should have the following structure: .filetree - .file angular2_tour_of_heroes + .file angular_tour_of_heroes .children .file lib .children diff --git a/public/docs/dart/latest/tutorial/toh-pt2.jade b/public/docs/dart/latest/tutorial/toh-pt2.jade index 24e38e31b3..8966b05dc1 100644 --- a/public/docs/dart/latest/tutorial/toh-pt2.jade +++ b/public/docs/dart/latest/tutorial/toh-pt2.jade @@ -1,7 +1,6 @@ include ../_util-fns :marked - # It Takes Many Heroes Our story needs more heroes. We’ll expand our Tour of Heroes app to display a list of heroes, allow the user to select a hero, and display the hero’s details. @@ -20,7 +19,7 @@ include ../_util-fns If not, we’ll need to go back to Part 1 and figure out what we missed. .filetree - .file angular2_tour_of_heroes + .file angular_tour_of_heroes .children .file lib .children diff --git a/public/docs/dart/latest/tutorial/toh-pt3.jade b/public/docs/dart/latest/tutorial/toh-pt3.jade index 7e7bd9911a..b338a0f43b 100644 --- a/public/docs/dart/latest/tutorial/toh-pt3.jade +++ b/public/docs/dart/latest/tutorial/toh-pt3.jade @@ -12,7 +12,7 @@ include ../_util-fns Before we continue with our Tour of Heroes, let’s verify we have the following structure. If not, we’ll need to go back and follow the previous chapters. .filetree - .file angular2_tour_of_heroes + .file angular_tour_of_heroes .children .file lib .children @@ -63,7 +63,7 @@ code-example(language="bash"). All of our component names end in "Component". All of our component file names end in "_component". We spell our filenames in lower **underscore case** - (AKA **[snake_case](../guide/glossary.html#!#snake_case)**) so we don't worry about + (AKA **[snake_case](../guide/glossary.html#snake_case)**) so we don't worry about case sensitivity on the server or in source control. - + 当然,我们也能编写自己的指令。像`HeroListComponent`这样的组件就是一种自定义指令。 .l-hr @@ -682,153 +678,151 @@ block dart-bool .l-main-section :marked ## Services - + ## 服务 - figure img(src="/resources/images/devguide/architecture/service.png" alt="服务" style="float:left; margin-left:-40px;margin-right:10px" ) :marked _Service_ is a broad category encompassing any value, function, or feature that your 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. - + 几乎任何东西都可以是一个服务。 典型的服务是一个类,具有专注的、良好定义的用途。它应该做一件具体的事情,把它做好。 -
+
:marked Examples include: - + 例如: - + * logging service - + * 日志服务 - + * data service - + * 数据服务 - + * message bus - + * 消息总线 - + * tax calculator - + * 税款计算器 - + * application configuration - + * 应用程序配置 - + There is nothing specifically _Angular_ about services. Angular has no definition of a service. There is no service base class, and no place to register a service. - + 服务没有什么特别属于*Angular*的特性。Angular对于服务也没有什么定义。 它甚至都没有定义服务的基类(Base Class),也没有地方注册一个服务。 - + Yet services are fundamental to any Angular application. Components are big consumers of services. - + 即便如此,服务仍然是任何Angular应用的基础。组件就是最大的*服务*消费者。 - + Here's an example of a service class that logs to the browser console: - + 这里是一个“服务”类的范例,用于把日志记录到浏览器的控制台: - + +makeExcerpt('app/logger.service.ts', 'class') :marked Here's a `HeroService` that fetches heroes and returns them in a resolved !{_PromiseLinked}. The `HeroService` depends on the `Logger` service and another `BackendService` that handles the server communication grunt work. - + 下面是`HeroService`类,用于获取英雄数据,并通过一个已解析的[承诺(Promise)](http://exploringjs.com/es6/ch_promises.html)返回它们。 `HeroService`还依赖于`Logger`服务和另一个用来处理服务器通讯工作的`BackendService`服务。 +makeExcerpt('app/hero.service.ts', 'class') :marked - Services are everywhere. - - 服务无处不在。 + Services are everywhere. + + 服务无处不在。 Component classes should be lean. They don't fetch data from the server, validate user input, or log directly to the console. They delegate such tasks to services. - + 我们更倾向于让组件保持精简。组件不需要从服务器获得数据、不需要验证输入,也不需要直接往控制台写日志。 它们把这些任务委托给了服务。 - + A component's job is to enable the user experience and nothing more. It mediates between the view (rendered by the template) and the application logic (which often includes some notion of a _model_). A good component presents properties and methods for data binding. It delegates everything nontrivial to services. - + 组件的任务就是提供用户体验,仅此而已。它介于视图(由模板渲染)和应用逻辑(通常包括_模型(model)_的观念)之间。 设计良好的组件为数据绑定提供属性和方法,把那些其它对它们不重要的事情都委托给服务。 Angular doesn't *enforce* these principles. It won't complain if you write a "kitchen sink" component with 3000 lines. - + Angular不会*强制要求*我们遵循这些原则。 即使我们花3000行代码写了一个“厨房洗碗槽”组件,它也不会抱怨什么。 - + Angular does help you *follow* these principles by making it easy to factor your application logic into services and make those services available to components through *dependency injection*. - + Angular帮助我们*追随*这些原则 —— 它让我们能更轻易的把应用逻辑拆分到服务,并通过*依赖注入*来在组件中使用这些服务。 .l-hr .l-main-section :marked - ## Dependency Injection - - ## 依赖注入 + ## Dependency injection + ## 依赖注入 figure img(src="/resources/images/devguide/architecture/dependency-injection.png" alt="服务" 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. - + “依赖注入”是提供类的新实例的一种方式,还负责处理好类所需的全部依赖。大多数依赖都是服务。 Angular也使用依赖注入提供我们需要的组件以及这些组件所需的服务。 - -
+ +
:marked Angular can tell which services a component needs by looking at the types of its constructor parameters. For example, the constructor of your `HeroListComponent` needs a `HeroService`: - + Angular能通过查看构造函数的参数类型,来得知组件需要哪些服务。 例如,`HeroListComponent`组件的构造函数需要一个`HeroService`: - + +makeExcerpt('app/hero-list.component.ts (constructor)', 'ctor') :marked When Angular creates a component, it first asks an **injector** for - the services that the component requires. - + the services that the component requires. + 当Angular创建组件时,会首先为组件所需的服务找一个**注入器(Injector)**。 - - An `injector` maintains a container of service instances that it has previously created. + + 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 *dependency injection*. - + 注入器是一个维护服务实例的容器,存放着以前创建的实例。 如果容器中还没有所请求的服务实例,注入器就会创建一个服务实例,并且添加到容器中,然后把这个服务返回给Angular。 当所有的服务都被解析完并返回时,Angular会以这些服务为参数去调用组件的构造函数。 这就是*依赖注入* 。 - + The process of `HeroService` injection looks a bit like this: - + `HeroService`注入的过程看起来有点像这样: - + figure img(src="/resources/images/devguide/architecture/injector-injects.png" alt="服务" ) :marked @@ -843,12 +837,12 @@ figure 提供商可以创建并返回服务,通常返回的就是这个“服务类”本身。 You can register providers in modules or in components. - + 我们可以在模块上或组件上注册提供商。 - + In general, add providers to the [root module](#module) so that the same instance of a service is available everywhere. - + 我们通常会把提供商添加到[根模块](#module)上,以便任何地方使用的都是服务的同一个实例。 +makeExample('app/app.module.ts', 'providers', 'app/app.module.ts (module providers)')(format='.') @@ -863,148 +857,147 @@ figure :marked Registering at a component level means you get a new instance of the service with each new instance of that component. - + 把它注册在组件级表示该组件的每一个新实例都会有一个(在该组件注册的)服务的新实例。 - + - + Points to remember about dependency injection: - + 需要记住的关于依赖注入的要点是: - + * Dependency injection is wired into the Angular framework and used everywhere. - + * 依赖注入渗透在整个Angular框架中,并且被到处使用。 - + * The *injector* is the main mechanism. - + * **注入器(Injector)**是本机制的核心。 - + * 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. - + * *提供商*是一个用于创建服务的“配方”。 - + * Register *providers* with injectors. - - * 把*提供商*注册到注入器。 + + * 把*提供商*注册到注入器。 .l-hr .l-main-section :marked ## Wrap up - + ## 总结 - + You've learned the basics about the eight main building blocks of an Angular application: - + 我们学到的这些只是关于Angular应用程序的八个主要构造块的基础知识: - - * [Modules](#modules) - - * [模块](#modules) - + + * [Modules](#modules) + + * [模块](#modules) + * [Components](#components) - + * [组件](#components) - + * [Templates](#templates) - + * [模板](#templates) - + * [Metadata](#metadata) - + * [元数据](#metadata) - + * [Data binding](#data-binding) - + * [数据绑定](#data-binding) - + * [Directives](#directives) - + * [指令](#directives) - + * [Services](#services) - + * [服务](#services) - + * [Dependency injection](#dependency-injection) - + * [依赖注入](#dependency-injection) - - - That's a foundation for everything else in an Angular application + + 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 you need to know. - + 这是Angular应用程序中所有其它东西的基础,要使用Angular 2,以这些作为开端就绰绰有余了。 但它仍然没有包含我们需要知道的全部。 - - Here is a brief, alphabetical list of other important Angular features and services. + + Here is a brief, alphabetical list of other important Angular features and services. Most of them are covered in this documentation (or soon will be). - + 这里是一个简短的、按字母排序的列表,列出了其它重要的Angular特性和服务。 它们大多数已经(或即将)包括在这份开发文档中: - + > [**Animations**](animations.html): Animate component behavior without deep knowledge of animation techniques or CSS with Angular's animation library. - + > [**动画**](animations.html):用Angular的动画库让组件动起来,而不需要对动画技术或CSS有深入的了解。 > **Change detection**: The change detection documentation will cover how Angular decides that a component property value has changed, when to update the screen, and how it uses **zones** to intercept asynchronous activity and run its change detection strategies. - > **变更检测**:“变更检测”文档会告诉你Angular是如何决定组件的属性值变化和什么时候该更新到屏幕的。 + > **变更检测**:“变更检测”文档会告诉你Angular是如何决定组件的属性值变化和什么时候该更新到屏幕的。 以及它是如何用**zones**来拦截异步行为并执行变更检测策略。 > **Events**: The events documentation will cover how to use components and services to raise events with mechanisms for publishing and subscribing to events. > **事件**:“事件”文档会告诉你如何使用组件和服务触发支持发布和订阅的事件。 - + > [**Forms**](forms.html): Support complex data entry scenarios with HTML-based validation and dirty checking. - + > [**表单**](forms.html):通过基于HTML的验证和脏检查机制支持复杂的数据输入场景。 - + > [**HTTP**](server-communication.html): Communicate with a server to get data, save data, and invoke server-side actions with an HTTP client. - + > [**HTTP**](server-communication.html):通过这个HTTP客户端,可以与服务器通讯,以获得数据、保存数据和触发服务端动作。 - + > [**Lifecycle hooks**](lifecycle-hooks.html): Tap into key moments in the lifetime of a component, from its creation to its destruction, by implementing the lifecycle hook interfaces. - + > [**生命周期钩子**](lifecycle-hooks.html):通过实现生命周期钩子接口,可以切入组件生命中的几个关键点:从创建到销毁。 - + > [**Pipes**](pipes.html): Use pipes in your templates to improve the user experience by transforming values for display. Consider this `currency` pipe expression: - + > [**管道**](pipes.html):在模板中使用管道转换成可显示的值,以增强用户体验。比如这个`currency`管道表达式: - +
code-example(). price | currency:'USD':true
:marked > It displays a price of "42.33" as `$42.33`. - + > 它把"42.33"显示为`$42.33`。 - + > [**Router**](router.html): Navigate from page to page within the client application and never leave the browser. - - > [**路由器**](router.html):在应用程序客户端导航,并且不离开浏览器。 - + + > [**路由器**](router.html):在应用程序客户端导航,并且不离开浏览器。 + > [**Testing**](testing.html): Run unit tests on your application parts as they interact with the Angular framework using the _Angular Testing Platform_. diff --git a/public/docs/ts/latest/guide/browser-support.jade b/public/docs/ts/latest/guide/browser-support.jade index 15932d2f4b..ed7afed1fd 100644 --- a/public/docs/ts/latest/guide/browser-support.jade +++ b/public/docs/ts/latest/guide/browser-support.jade @@ -3,12 +3,10 @@ block includes - var _at_angular = '@angular' :marked - # Browser support # - # 浏览器支持 # - Angular supports most recent browsers. This includes the following specific versions: Angular支持大多数常用浏览器,包括下列版本: + table tr th Chrome @@ -20,8 +18,12 @@ table th Android th IE mobile tr - td 最新版 - td 最新版 + td + p latest + p 最新版 + td + p latest + p 最新版 td 14 td 11 td 10 @@ -55,64 +57,64 @@ table td 7 td Jelly Bean
(4.1, 4.2, 4.3) td - - + .l-sub-section :marked Angular's continuous integration process runs unit tests of the framework on all of these browsers for every pull request, using SauceLabs and Browserstack. - - Angular在持续集成过程中,对每一个提交都会使用SauceLabs和 + + Angular在持续集成过程中,对每一个提交都会使用SauceLabsBrowserstack在上述所有浏览器上执行单元测试。 :marked - # Polyfills # - # 填充库(Polyfill) # + ## Polyfills # + ## 填充库(Polyfill) # Angular is built on the latest standards of the web platform. Targeting such a wide range of browsers is challenging because they do not support all features of modern browsers. - + Angular构建于Web平台的最新标准之上。 要支持这么多浏览器是一个不小的挑战,因为它们不支持现代浏览器的所有特性。 - + You compensate by loading polyfill scripts ("polyfills") on the host web page (`index.html`) that implement missing features in JavaScript. - + 你可以通过在宿主页面(`index.html`)中加载填充脚本(“polyfills”)来加以弥补,这些脚本实现了浏览器缺失的JavaScript特性。 - + +makeExample('quickstart/ts/index.html', 'polyfills')(format='.') :marked A particular browser may require at least one polyfill to run _any_ Angular application. You may need additional polyfills for specific features. - + 要运行Angular应用,某些浏览器可能需要至少一个填充库。除此之外,如果要支持某些特定的特性,你可能还需要另一些填充库。 The tables below will help you determine which polyfills to load, depending on the browsers you target and the features you use. - + 下表将帮你决定该加载哪些填充库,具体取决于目标浏览器和要用到的特性。 - + .alert.is-important :marked The suggested polyfills are the ones we know will run full Angular applications. You may need additional polyfills to support features not covered by this list. Note that polyfills cannot magically transform an old, slow browser into a modern, fast one. - + 这些建议的填充库假设你运行的是完全由Angular书写的应用。 你可能还会需要另一些的填充库来支持没有出现在此列表中的哪些特性。 注意,这些填充库并没有神奇的魔力来把老旧、慢速的浏览器变成现代、快速的浏览器,它只是填充了API。 - + :marked - ## Mandatory polyfills ## - ## 强制性填充库 ## + ### Mandatory polyfills ## + ### 强制性填充库 ## These are the polyfills required to run an Angular application on each supported browser: - + 下表是填充库对每个支持的浏览器都是需要的: + table tr(style="vertical-align: top") - th + th p Browsers (desktop & mobile) - p 浏览器(桌面 & 移动) - th + p 浏览器(桌面和移动) + th p Polyfills required p 需要的填充库 tr(style="vertical-align: top") @@ -130,44 +132,43 @@ table [ES6
classList](#classlist) :marked - ## Optional browser features to polyfill ## - ## 可选浏览器特性的填充库 ## + ### Optional browser features to polyfill ## + ### 可选浏览器特性的填充库 ## Some features of Angular may require additional polyfills. - + 有些Angular特性可能需要更多填充库。 - + For example, the animations library relies on the standard web animation API, which is only available in Chrome and Firefox today. You'll need a polyfill to use animations in other browsers. - + 比如,动画库依赖于标准的动画API,目前它只在Chrome和Firefox上可用。你可能需要一个填充库来在其它浏览器上使用动画功能。 - + Here are the features which may require additional polyfills: 下列特性可能需要更多填充库: - + table tr(style="vertical-align: top") - th + th p Feature p 特性 - th + th p Polyfill p 填充库 - th(style="width: 50%") + th(style="width: 50%") p Browsers (desktop & mobile) - p 浏览器(桌面 & 移动) + p 浏览器(桌面和移动) tr(style="vertical-align: top") td - a(href="./animations.html") Animations - a(href="./animations.html") 动画 + p a(href="./animations.html") Animations + p a(href="./animations.html") 动画 td :marked [Web Animations](#web-animations) - - [Web Animations](#web-animations) - - td + + [Web动画](#web-animations) + td p All but Chrome and Firefox
Not supported in IE9 p 除Chrome和Firefox外的所有,但不支持IE9 tr(style="vertical-align: top") @@ -177,34 +178,33 @@ table a(href="../api/common/index/CurrencyPipe-pipe.html" target="_blank") currency span , a(href="../api/common/index/DecimalPipe-pipe.html" target="_blank") decimal - span 和 + span 和 a(href="../api/common/index/PercentPipe-pipe.html" target="_blank") percent - span 管道 + span 管道 td :marked [Intl API](#intl) - td - p All but Chrome, Firefox, Edge, E11 and Safari 10 + td + p All but Chrome, Firefox, Edge, IE11 and Safari 10 p 除了Chrome、Firefox、Edge、IE11和Safari 10外的所有浏览器 tr(style="vertical-align: top") - td - p + td + p. a(href="../api/common/index/NgClass-directive.html" target="_blank") NgClass span on SVG elements - p - | 在SVG元素上用 - a(href="../api/common/index/NgClass-directive.html" target="_blank") NgClass + p. + 在SVG元素上用a(href="../api/common/index/NgClass-directive.html" target="_blank") NgClass td :marked [classList](#classlist) td IE10, IE11 tr(style="vertical-align: top") td - p + p. a(href="./server-communication.html") Http span when sending and receiving binary data - p - span 用 + p. + span 用 a(href="./server-communication.html") Http span 发送和接受二进制数据 td @@ -213,21 +213,21 @@ table td IE 9 :marked - ## Suggested polyfills ## - ## 建议的填充库 ## - + ### Suggested polyfills ## + ### 建议的填充库 ## Below are the polyfills which are used to test the framework itself. They are a good starting point for an application. 下表中是用来测试框架本身的填充库,它们是应用程序的优质起点。 + table tr - th + th p Polyfill p 填充库 - th + th p Licence p 授权方式 - th + th p Size* p 大小* tr @@ -238,7 +238,7 @@ table tr td a#classlist(href="https://github.com/eligrey/classList.js" target="_blank") classList - td + td p Public domain p 公共域 td 1KB @@ -249,17 +249,17 @@ table td 13.5KB tr td - p + p. a(href="https://github.com/web-animations/web-animations-js" target="_blank") Web Animations - p + p. a#web-animations(href="https://github.com/web-animations/web-animations-js" target="_blank") Web Animations td Apache td 14.8KB tr td - p + p. a(href="https://github.com/inexorabletash/polyfill/blob/master/typedarray.js" target="_blank") Typed Array - p + p. a#typedarray(href="https://github.com/inexorabletash/polyfill/blob/master/typedarray.js" target="_blank") Typed Array td MIT td 4KB diff --git a/public/docs/ts/latest/guide/change-log.jade b/public/docs/ts/latest/guide/change-log.jade index 59b1c43516..b752879ce2 100644 --- a/public/docs/ts/latest/guide/change-log.jade +++ b/public/docs/ts/latest/guide/change-log.jade @@ -2,22 +2,54 @@ block includes include ../_util-fns :marked - # Documentation Change Log - - # 文档变更日志 - The Angular documentation is a living document with continuous improvements. This log calls attention to recent significant changes. 我们将持续不断的更新和改进Angular文档。本日志记录了近期最重要的变更。 + ## Sync with Angular v.2.2.0 (2016-11-14) + + ## 与Angular v.2.2.0同步(2016-11-14) + + Docs and code samples updated and tested with Angular v.2.2.0 + + 使用Angular v.2.2.0更新和测试所有文档和代码例子。 + + ## UPDATE: NgUpgrade Guide for the AoT friendly _upgrade/static_ module (2016-11-14) + + ## 更新:用于AoT的_upgrade/static_模块NgUpgrade指南 (2016-11-14) + + The updated [NgUpgrade Guide](upgrade.html) guide covers the + new AoT friendly `upgrade/static` module + released in v.2.2.0, which is the recommended + facility for migrating from Angular 1 to Angular 2. + The documentation for the version prior to v.2.2.0 has been removed. + + 更新的[NgUpgrade指南](upgrade.html)覆盖在v.2.2.0发布的AoT`upgrade/static`模块, + 是从Angular 1升级至Angular 2的推荐工具。 + 删除早于v.2.2.0版本的文档。 + + ## ES6 described in "TypeScript to JavaScript" (2016-11-14) + + ## 在"从TypeScript到JavaScript"增加ES6的描述 (2016-11-14) + + The updated "[TypeScript to JavaScript](../cookbook/ts-to-js.html)" cookbook + now explains how to write apps in ES6/7 + + 更新了"[从TypeScript到JavaScript](../cookbook/ts-to-js.html)"烹饪宝典,解释如何使用ES6/7编写应用 + + by translating the common idioms in the TypeScript documentation examples + (and elsewhere on the web) to ES6/7 and ES5. + + 将TypeScript文档示例中(以及网站其它地方)的习惯用法翻译成ES6/7和ES5。 + ## Sync with Angular v.2.1.1 (2016-10-21) ## 与Angular v.2.1.1 同步(2016-10-21) - - Docs and code samples updated and tested with Angular v.2.1.0 - - 使用Angular v.2.1.1更新和测试所有文档和代码例子。 + + Docs and code samples updated and tested with Angular v.2.1.0 + + 使用Angular v.2.1.1更新和测试所有文档和代码例子。 ## npm _@types_ packages replace _typings_ (2016-10-20) @@ -26,59 +58,59 @@ block includes Documentation samples now get TypeScript type information for 3rd party libraries from npm `@types` packages rather than with the _typings_ tooling. The `typings.json` file is gone. - + 文档例子现在从npm的`@types`第三方库获取TypeScript类型信息,不再使用_typings_。 删除`typings.json`文件。 The "[Angular 1 Upgrade](upgrade.html)" guide reflects this change. The `package.json` installs `@types/angular` and several `@types/angular-...` packages in support of upgrade; these are not needed for pure Angular 2 development. - + "[从1.x升级](upgrade.html)"指南反映了这个变化。 `package.json`安装`@types/angular`和一些`@types/angular-...`包来支持升级。它们在纯Angular 2开发中是不需要的。 ## "Template Syntax" explains two-way data binding syntax (2016-10-20) ## "模板语法"添加了双向数据绑定语法的解释(2016-10-20) - + Demonstrates how to two-way data bind to a custom Angular component and re-explains `[(ngModel)]` in terms of the basic `[()]` syntax. - + 展示了如何在自定义Angular组件中双向数据绑定,用基础`[()]`重新解释`[(ngModel)]`。 ## BREAKING CHANGE: `in-memory-web-api` (v.0.1.11) delivered as esm umd (2016-10-19) - + ## 破坏性变化:`in-memory-web-api` (v.0.1.11) 以esm umd的形式发布 (2016-10-19) - + This change supports ES6 developers and aligns better with typical Angular libraries. It does not affect the module's API but it does affect how you load and import it. See the change note in the `in-memory-web-api` repo. - + 这个变化支持ES6开发者,并与典型的Angular库看齐。 它不会影响模块的API,但是它改变了加载和导入它的方式。 参见`in-memory-web-api`库的变更记录。 ## "Router" _preload_ syntax and _:enter_/_:leave_ animations (2016-10-19) - + ## "路由器"_预加载_语法和_:enter_/_:leave_动画(2016-10-19) - + The router can lazily _preload_ modules _after_ the app starts and _before_ the user navigates to them for improved perceived performance. - + 路由器可以在应用启动_之后_和用户导航到惰性加载模块_之前_,预先加载惰性模块,以增强性能。 - - New `:enter` and `:leave` aliases make animation more natural. - + + New `:enter` and `:leave` aliases make animation more natural. + 新`:enter`和`:leave`语法,让动画更加自然。 ## Sync with Angular v.2.1.0 (2016-10-12) ## 与Angular v.2.1.0同步(2016-10-12) - - Docs and code samples updated and tested with Angular v.2.1.0 - 使用Angular v.2.1.0更新和测试所有文档和代码例子。 + Docs and code samples updated and tested with Angular v.2.1.0 + + 使用Angular v.2.1.0更新和测试所有文档和代码例子。 ## NEW "Ahead of Time (AoT) Compilation" cookbook (2016-10-11) @@ -93,12 +125,12 @@ block includes 它以**快速开始**应用程序开始讲解,接着介绍了编译和构建**英雄指南**的更高级的注意事项。 ## Sync with Angular v.2.0.2 (2016-10-6) - - ## 与Angular v.2.0.2同步 (2016-10-6) - - Docs and code samples updated and tested with Angular v.2.0.2 - 使用Angular v.2.0.2更新和测试所有文档和代码例子。 + ## 与Angular v.2.0.2同步 (2016-10-6) + + Docs and code samples updated and tested with Angular v.2.0.2 + + 使用Angular v.2.0.2更新和测试所有文档和代码例子。 ## "Routing and Navigation" guide with the _Router Module_ (2016-10-5) @@ -174,7 +206,7 @@ block includes 在所有使用`templateUrl`或者`styleUrls`来获取模板或样式的例子组件都被转换为**相对模块**的URL。 我们添加了`moduleId: module.id`到它们的`@Component`元数据。 - + This change is a requirement for compilation with AoT compiler when the app loads modules with SystemJS as the samples currently do. @@ -184,7 +216,7 @@ block includes ## 简化了“生命周期钩子”章(2016-09-24) - The [Lifecycle Hooks](lifecycle-hooks.html) guide is shorter, simpler, and + The [Lifecycle Hooks](lifecycle-hooks.html) guide is shorter, simpler, and draws more attention to the order in which Angular calls the hooks. [生命周期钩子](lifecycle-hooks.html)章现在更加简短,并且对强调了Angular是以什么顺序来调用钩子方法的。 diff --git a/public/docs/ts/latest/guide/dependency-injection.jade b/public/docs/ts/latest/guide/dependency-injection.jade index 47ca883ce0..8f7e40d2d0 100644 --- a/public/docs/ts/latest/guide/dependency-injection.jade +++ b/public/docs/ts/latest/guide/dependency-injection.jade @@ -147,7 +147,8 @@ block includes block ctor-syntax .l-sub-section :marked - We also leverage TypeScript's constructor syntax for declaring parameters and properties simultaneously. + We also leveraged TypeScript's constructor syntax for declaring + parameters and properties simultaneously. 我们再次借助TypeScript的构造器语法来同时定义参数和属性。 @@ -369,7 +370,7 @@ block ctor-syntax .l-sub-section :marked We aren't even pretending this is a real service. - If we were actually getting data from a remote server, the API would have to be + If we were actually getting data from a remote server, the API would have to be asynchronous, #{_perhaps} returning a !{_PromiseLinked}. We'd also have to rewrite the way components consume our service. This is important in general, but not to our current story. @@ -409,19 +410,19 @@ block ctor-syntax 在此之前,我们先来看一个在启动期间注册提供商的例子。 We can either register a provider within an [NgModule](ngmodule.html) or in application components - + 我们或者在[NgModule](ngmodule.html)中注册提供商,或者在应用组件中。 ### Registering providers in an NgModule - + ### 在NgModule中注册提供商。 - - Here's our AppModule where we register a `Logger`, an `UserService`, and an `APP_CONFIG` provider. - + + Here's our AppModule where we register a `Logger`, a `UserService`, and an `APP_CONFIG` provider. + 在AppModule中,我们注册了`Logger`、`UserService`和`APP_CONFIG`提供商。 - var stylePattern = { otl: /(providers)/ }; - + +makeExample('dependency-injection/ts/app/app.module.ts', 'ngmodule','app/app.module.ts', stylePattern)(format='.') <router-outlet></router-outlet> - + <!-- Routed views go here --> :marked ### Router Links @@ -334,7 +332,7 @@ code-example(language="html"). We add a **`RouterLink`** directive to the anchor tag. Since we know our link doesn't contain any dynamic information, we can use a one-time binding to our route *path*. - + 我们往A标签上添加了**`RouterLink`**指令。由于我们知道链接中不包含任何动态信息,因此我们使用一次性绑定的方式把它绑定到我们路由中的*path*值。 If our `RouterLink` needed to be more dynamic we could bind to a template expression that @@ -347,7 +345,7 @@ code-example(language="html"). We also add a **`RouterLinkActive`** directive to each anchor tag to add or remove CSS classes to the element when the associated *RouterLink* becomes active. The directive can be added directly on the element or on its parent element. - + 我们还往每个A标签上添加了一个**`RouterLinkActive`**指令,用于在相关的*RouterLink*被激活时为所在元素添加或移除CSS类。 该指令可以直接添加到该元素上,也可以添加到其父元素上。 @@ -375,25 +373,25 @@ code-example(language="html"). We define `active` as the CSS class we want toggled to each `RouterLink` when they become the current route using the `RouterLinkActive ` directive. We could add multiple classes to the `RouterLink` if we so desired. - + 利用`RouterLinkActive`指令,我们把`active`作为当路由被激活时为`RouterLink`切换的CSS类。 必要时,还可以为`RouterLink`添加多个类。 :marked ### Router State - + ### 路由器状态 - + After the end of each successful navigation lifecycle, the router builds a tree of `ActivatedRoute` objects that make up the current state of the router. We can access the current `RouterState` from anywhere in our application using the `Router` service and the `routerState` property. - + 在导航时的每个生命周期成功完成时,路由器会构建出一个`ActivatedRoute`组成的树,它表示路由器的当前状态。 我们可以在应用中的任何地方用`Router`服务及其`routerState`属性来访问当前的`RouterState`值。 Each `ActivatedRoute` in the `RouterState` provides methods to traverse up and down the route tree to get information we may need from parent, child and sibling routes. - + 路由器状态为我们提供了从任意激活路由开始向上或向下遍历路由树的一种方式,以获得关于父、子、兄弟路由的信息。 :marked @@ -415,42 +413,30 @@ code-example(language="html"). table tr - th + th p Router Part - p 路由器部件 - - th + th p Meaning - p 含义 - tr - td - p Router - - p Router(路由器) - td + p Router + p Router(路由器) + td. p. Displays the application component for the active URL. Manages navigation from one component to the next. - p 为激活的URL显示应用组件。管理从一个组件到另一个组件的导航 - tr - td + td p RouterModule - p RouterModule(路由器模块) - td p. A separate Angular module that provides the necessary service providers and directives for navigating through application views. - p 一个独立的Angular模块,用于提供所需的服务提供商,以及用来在应用视图之间进行导航的指令。 - tr td p Routes @@ -460,52 +446,39 @@ table Defines an array of Routes, each mapping a URL path to a component. p 定义了一个路由数组,每一个都会把一个URL路径映射到一个组件。 tr - td + td p Route - p Route(路由) - td p. Defines how the router should navigate to a component based on a URL pattern. Most routes consist of a path and a component type. - p 定义路由器该如何根据URL模式(pattern)来导航到组件。大多数路由都由路径和组件类构成。 - tr - td + td p RouterOutlet - p RouterOutlet(路由插座) - td p. The directive (<router-outlet>) that marks where the router should display a view. - p 该指令(<router-outlet>)用来标记出路由器该在哪里显示视图。 tr - td + td p RouterLink - p RouterLink(路由链接) - td p. The directive for binding a clickable HTML element to a route. Clicking an anchor tag with a routerLink directive that is bound to a Link Parameters Array triggers a navigation. - - p. + p. 该指令用来把一个可点击的HTML元素绑定到路由。 点击带有绑定到字符串链接参数数组routerLink指令的A标签就会触发一次导航。 - tr - td + td p RouterLinkActive - p RouterLinkActive(活动路由链接) - td p. The directive for adding/removing classes from an HTML element when an associated @@ -521,41 +494,32 @@ table A service that is provided to each route component that contains route specific information such as route parameters, static data, resolve data, global query params and the global fragment. p 为每个路由组件提供提供的一个服务,它包含特定于路由的信息,比如路由参数、静态数据、解析数据、全局查询参数和全局碎片(fragment)。 - td - p RouterState - - p RouterState(路由器状态) - + tr + td + p RouterState + p RouterState(路由器状态) td p. The current state of the router including a tree of the currently activated routes in our application along convenience methods for traversing the route tree. p 路由器的当前状态包含了一棵由程序中激活的路由构成的树。它包含一些用于遍历路由树的快捷方法。 tr - td + td p Link Parameters Array - p 链接参数数组 - td p. An array that the router interprets into a routing instruction. We can bind a RouterLink to that array or pass the array as an argument to the Router.navigate method. - p 这个数组会被路由器解释成一个路由操作指南。我们可以把一个RouterLink绑定到该数组,或者把它作为参数传给Router.navigate方法。 - tr - td + td p Routing Component - p 路由组件 - td p An Angular component with a RouterOutlet that displays views based on router navigations. - p 一个带有RouterOutlet的Angular组件,它根据路由器的导航来显示相应的视图。 - :marked We've barely touched the surface of the router and its capabilities. @@ -584,13 +548,13 @@ table While we make incremental progress toward the ultimate sample application, this chapter is not a tutorial. We discuss code and design decisions pertinent to routing and application design. We gloss over everything in between. - + 虽然我们会渐进式的前进到最终的范例应用,但本章并不是一个教程。 我们讨论路由和应用设计有关的代码和设计决策,并在这期间,处理遇到的所有问题。 - + The full source is available in the . - - 完整代码可以在在线例子中找到。 + + 完整代码可以在在线例子中找到。 :marked Our client is the Hero Employment Agency. @@ -608,13 +572,13 @@ table 1. 一个*危机中心*区,它维护一个危机列表,用来分派给英雄。 1. A *Heroes* area where we maintain the list of heroes employed by The Agency. - + 1. 一个*英雄*区,它维护由英雄管理局雇佣的英雄列表。 - + 1. An *Admin* area where we manage the list of crises and heroes displayed. 1. 一个*管理*区,用来维护该中心危机列表和雇佣英雄的列表。 - + Run the . It opens in the *Crisis Center*. We'll come back to that. @@ -671,14 +635,14 @@ figure.image-display 这和*英雄详情*页略有不同。*英雄详情*会立即保存我们所做的更改。 而*危机详情*页中,我们的更改都是临时的 —— 除非按“保存”按钮保存它们,或者按“取消”按钮放弃它们。 这两个按钮都会导航回*危机中心*,显示危机列表。 - + Suppose we click a crisis, make a change, but ***do not click either button***. Maybe we click the browser back button instead. Maybe we click the "Heroes" link. - + 假如我们点击一个危机、做了修改,但是***没有点击任何按钮***,可能点击了浏览器的后退按钮,也可能点击了“英雄”链接。 - + Do either. Up pops a dialog box. - + 无论哪种情况,我们都应该弹出一个对话框。 figure.image-display @@ -717,9 +681,9 @@ figure.image-display 该应用展示了本章中涉及到的所有路由器特性: * organizing the application features into modules - + * 把应用的特性组织成模块 - + * navigating to a component (*Heroes* link to "Heroes List") * 导航到一个组件(*英雄*链接到“英雄列表”) @@ -737,23 +701,23 @@ figure.image-display * `CanActivate`守卫(检查路由访问权) * the `CanActivateChild` guard (checking child route access) - + * `CanActivateChild`守卫(检查子路由访问权) - + * the `CanDeactivate` guard (ask permission to discard unsaved changes) - + * `CanDeactivate`守卫(询问是否丢弃未保存的修改) - + * the `Resolve` guard (pre-fetching route data) - + * `Resolve`守卫(预先获取路由数据) - + * lazy loading feature modules - + * 惰性加载特性路由 - + * the `CanLoad` guard (check before loading feature module assets) - + * `CanLoad`守卫(在加载特性模块之前进行检查) @@ -838,26 +802,28 @@ a#base-href 我们只应该在在线例子这种情况下使用这种小花招,不要把它用到产品的正式代码中。 +a#import :marked ### Configure the routes for the Router ### 为路由器配置一些路由 - We begin by importing some symbols from the router library. - + 我们先从路由库中导入一些符号。 The Router is in its own `@angular/router` package. It's not part of the Angular core. The router is an optional service because not all applications need routing and, depending on your requirements, you may need a different routing library. - + 路由器在它自己的`@angular/router`包中。 它不是Angular 2内核的一部分。该路由器是可选的服务,这是因为并不是所有应用都需要路由,并且,如果需要,你还可能需要另外的路由库。 - We teach our router how to navigate by configuring it with routes. - - 通过一些路由来配置路由器,我们可以教它如何进行导航。 + We teach our router how to navigate by configuring it with routes. + + 通过一些路由来配置路由器,我们可以教它如何进行导航。 + + 通过一些路由来配置路由器,我们可以教它如何进行导航。 a#route-config @@ -900,7 +866,7 @@ h4#define-routes 定义一些路由 for that path.* * **当应用程序请求导航到路径`/crisis-center`时,创建或者取回一个`CrisisListComponent`的实例,显示它的视图,并将该路径更新到浏览器地址栏和历史。** - + :marked Here is our first configuration. We pass the array of routes to the `RouterModule.forRoot` method which returns a module containing the configured `Router` service provider ... and some other, @@ -915,7 +881,7 @@ h4#define-routes 定义一些路由 :marked Adding the configured `RouterModule` to the `AppModule` is sufficient for simple route configurations. As our application grows, we'll want to refactor our routing configuration into a separate file - and create a **[Routing Module](#routing-module)**, a special type of `Service Module` dedicating for the purpose + and create a **[Routing Module](#routing-module)**, a special type of `Service Module` dedicated for the purpose of routing in feature modules. 作为简单的路由配置,将添加配置好的`RouterModule`到`AppModule`中就足够了。 @@ -923,9 +889,8 @@ h4#define-routes 定义一些路由 :marked Providing the `RouterModule` in our `AppModule` makes the Router available everywhere in our application. - + 在`AppModule`中提供`RouterModule`,让该路由器在应用的任何地方都能被使用。 - h3#shell The AppComponent shell @@ -979,22 +944,22 @@ a#router-link The links in this example each have a string path, the path of a route that we configured earlier. We don't have route parameters yet. - + 例子中的每个链接都有一个字符串型的路径,也就是我们以前配置过的路由路径,但还没有指定路由参数。 We can also add more contextual information to our `RouterLink` by providing query string parameters or a URL fragment for jumping to different areas on our page. Query string parameters are provided through the `[queryParams]` binding which takes an object (e.g. `{ name: 'value' }`), while the URL fragment takes a single value bound to the `[fragment]` input binding. - + 我们还可以通过提供查询字符串参数为`RouterLink`提供更多情境信息,或提供一个URL片段(Fragment或hash)来跳转到本页面中的其它区域。 查询字符串可以由`[queryParams]`绑定来提供,它需要一个对象型参数(如`{ name: 'value' }`),而URL片段需要一个绑定到`[fragment]`的单一值。 - + .l-sub-section :marked Learn about the how we can also use the **link parameters array** in the [appendix below](#link-parameters-array). - + 还可以到[后面的附录](#link-parameters-array)中学习如何使用**链接参数数组**。 a#router-link-active @@ -1006,20 +971,20 @@ h3#router-link RouterLinkActive绑定 :marked On each anchor tag, we also see [Property Bindings](template-syntax.html#property-binding) to the `RouterLinkActive` directive that look like `routerLinkActive="..."`. - + 每个A标签还有一个到`RouterLinkActive`指令的[属性绑定](template-syntax.html#property-binding),就像`routerLinkActive="..."`。 The template expression to the right of the equals (=) contains our space-delimited string of CSS classes. We can also bind to the `RouterLinkActive` directive using an array of classes such as `[routerLinkActive]="['...']"`. - + 等号(=)右侧的模板表达式包含用空格分隔的一些CSS类。我们还可以把`RouterLinkActive`指令绑定到一个CSS类组成的数组,如`[routerLinkActive]="['...']"`。 The `RouterLinkActive` directive toggles css classes for active `RouterLink`s based on the current `RouterState`. This cascades down through each level in our route tree, so parent and child router links can be active at the same time. To override this behavior, we can bind to the `[routerLinkActiveOptions]` input binding with the `{ exact: true }` expression. By using `{ exact: true }`, a given `RouterLink` will only be active if its URL is an exact match to the current URL. - + `RouterLinkActive`指令会基于当前的`RouterState`对象来为激活的`RouterLink`切换CSS类。 这会一直沿着路由树往下进行级联处理,所以父路由链接和子路由链接可能会同时激活。 要改变这种行为,可以把`[routerLinkActiveOptions]`绑定到`{exact: true}`表达式。 @@ -1032,7 +997,7 @@ h3#router-directives 路由器指令集 :marked `RouterLink`, `RouterLinkActive` and `RouterOutlet` are directives provided by the Angular `RouterModule` package. They are readily available for us to use in our template. - + `RouterLink`、`RouterLinkActive`和`RouterOutlet`是由`RouterModule`包提供的指令。 现在它已经可用于我们自己的模板中。 :marked @@ -1154,7 +1119,7 @@ h3#router-directives 路由器指令集 * 为路由服务提供商(包括守卫和解析器等)提供一个共同的地方 - * is **not** concerned with feature [module declarations](../cookbook/ngmodule-faq.html#!#routing-module) + * is **not** concerned with feature [module declarations](../cookbook/ngmodule-faq.html#routing-module) * 与特征的[声明](../cookbook/ngmodule-faq.html#!#routing-module)**无关** @@ -1214,7 +1179,7 @@ a#why-routing-module ### Do you need a _Routing Module_? ### 你需要**路由模块**吗? - + The _Routing Module_ *replaces* the routing configuration in the root or feature module. _Either_ configure routes in the Routing Module _or_ within the module itself but not in both. @@ -1227,11 +1192,11 @@ a#why-routing-module 路由模块是设计选择,它的价值在配置很复杂,并包含专门守卫和解析器服务时尤其明显。 在配置很简单时,它可能看起来很多余。 - Some developers skip the Routing Module (e.g., `AppRoutingModule`) when the configuration is simple and + Some developers skip the Routing Module (e.g., `AppRoutingModule`) when the configuration is simple and merge the routing configuration directly into the companion module (e.g., `AppModule`). 在配置很简单时,一些开发者跳过路由模块(例如`AppRoutingModule`),并将路由配置直接混合在关联模块中(比如`AppModule` )。 - + We recommend that you choose one pattern or the other and follow that pattern consistently. 我们建议你选择其中一种模式,并坚持模式的一致性。 @@ -1253,8 +1218,8 @@ a#why-routing-module .l-main-section#heroes-feature :marked ## Milestone #3: The Heroes Feature - - ## 里程碑 #2 英雄特征区 + + ## 里程碑 #2 英雄特征区 We've seen how to navigate using the `RouterLink` directive. @@ -1322,7 +1287,7 @@ figure.image-display We want to break our app out into different *feature modules* that we then import into our main module so it can make use of them. First, we'll create a `heroes.module.ts` in our heroes folder. - + 我们要把应用拆成不同的*特性模块*,然后把它们导入我们的主模块中,以便使用它们。首先,我们要在heroes目录下创建一个`heroes.module.ts`文件。 We delete the placeholder `hero-list.component.ts` that's in @@ -1334,19 +1299,19 @@ figure.image-display folder and copy over the contents of the final `heroes.component.ts` from the tutorial. We copy the `hero-detail.component.ts` and the `hero.service.ts` files into the `heroes/` folder. - + 然后在`app/heroes/`目录下创建了一个`hero-list.component.ts`文件,并从上面的教程中把`heroes.component.ts`最终版的内容拷贝进来。 再把`hero-detail.component.ts`和`hero.service.ts`文件拷贝到`heroes/`目录下。 We provide the `HeroService` in the `providers` array of our `Heroes` module so its available to all components within our module. - + 我们在`Heroes`模块的`providers`数组中提供了`HeroService`,以便它可用于模块中的所有组件。 Our `Heroes` module is ready for routing. - + 我们的`Heroes`模块准备好路由了。 - + +makeExcerpt('app/heroes/heroes.module.1.ts') :marked @@ -1408,7 +1373,7 @@ figure.image-display :marked Keep the Routing Module file in the same folder as its companion module file. Here both `heroes-routing.module.ts` and `heroes.module.ts` are in the same `app/heroes` folder. - + 将路由模块文件放到它相关的模块文件所在目录里。 这里,`heroes-routing.module.ts`和`heroes.module.ts`都在`app/heroes`目录中。 @@ -1427,7 +1392,7 @@ figure.image-display We'll import the *RouterModule* like we did in the `app-routing.module.ts`, but there is a slight difference here. In our `app-routing.module.ts`, we used the static **forRoot** method to register our routes and application level service providers. In a feature module we use static **forChild** method. - + 现在,我们的`Heroes`模块有路由了,我们得用*路由器*注册它们。 我们像在`app.routing.ts`中那样导入*RouterModule*,但这里稍微有一点不同。 在设置`app.routing.ts`时,我们使用了静态的**forRoot**方法来注册我们的路由和全应用级服务提供商。 @@ -1437,13 +1402,13 @@ figure.image-display :marked The **RouterModule.forRoot** should only be provided for the `AppModule`. Since we are in a feature module, we'll use **RouterModule.forChild** method to only register additional routes. - + **RouterModule.forRoot**只能由`AppModule`提供。但我们位于特性模块中,所以使用**RouterModule.forChild**来单独注册更多路由。 :marked We import our `HeroRoutingModule` token from `heroes-routing.module.ts` into our `Heroes` module and register the routing. - - 我们在`Heroes`模块中从`heroes-routing.module.ts`中导入`HeroRoutingModule`,并注册其路由。 + + 我们在`Heroes`模块中从`heroes-routing.module.ts`中导入`HeroRoutingModule`,并注册其路由。 +makeExcerpt('app/heroes/heroes.module.ts (heroes routing)', 'heroes-routes') @@ -1482,9 +1447,9 @@ code-example(format="." language="bash"). :marked #### Route parameter: Required or optional? - + #### 路由参数:必选还是可选? - + Embedding the route parameter token, `:id`, in the route definition path is a good choice for our scenario because the `id` is *required* by the `HeroDetailComponent` and because the value `15` in the path clearly distinguishes the route to "Magneta" from @@ -1494,13 +1459,13 @@ code-example(format="." language="bash"). 而且路径中的值`15`已经足够把到“Magneta”的路由和到其它英雄的路由明确区分开。 An [optional-route-parameter](#optional-route-parameters) might be a better choice if we were passing an *optional* value to `HeroDetailComponent`. - + 当我们把一个*可选*值传给`HeroDetailComponent`时,[可选路由参数](#optional-route-parameters)可能是一个更好的选择。 - + a#navigate :marked ### Navigate to hero detail imperatively - + ### 命令式地导航到英雄详情 *We won't navigate to the detail component by clicking a link* @@ -1591,66 +1556,70 @@ h3#activated-route ActivatedRoute:一站式获得路由信息 :marked Each route contains information about its path, data parameters, URL segment and much more. All of this information is available in an injected service provided by the router called the [ActivatedRoute](../api/router/index/ActivatedRoute-interface.html). - + 每个路由都包含路径、数据参数、URL片段等很多信息。 所有这些信息都可以通过有路由器提供的一个叫[ActivatedRoute](../api/router/index/ActivatedRoute-interface.html)的服务提供商来获取。 The `ActivatedRoute` contains all the information you need from the current route component as well as ways to get information about other activated routes in the `RouterState`. - + `ActivatedRoute`包含你需要从当前路由组件中获得的全部信息,正如你可以从`RouterState`中获得关于其它激活路由的信息。 .l-sub-section :marked **`url`**: An `Observable` of the route path(s). The value is provided as an array of strings for each part of the route path. - + **`url`**: 该路由路径的`Observable`对象。它的值是一个由路径中各个部件组成的字符串数组。 **`data`**: An `Observable` that contains the `data` object provided for the route. Also contains any resolved values from the [resolve guard](#resolve-guard). - + **`data`**: 该路由提供的`data`对象的一个`Observable`对象。还包含从[resolve守卫](#resolve-guard)中解析出来的值。 **`params`**: An `Observable` that contains the required and [optional parameters](#optional-route-parameters) specific to the route. - + **`params`**: 包含该路由的必选参数和[可选参数](#optional-route-parameters)的`Observable`对象。 **`queryParams`**: An `Observable` that contains the [query parameters](#query-parameters) available to all routes. - + **`queryParams`**: 一个包含对所有路由都有效的[查询参数](#query-parameters)的`Observable`对象。 **`fragment`**: An `Observable` of the URL [fragment](#fragment) available to all routes. - + **`fragment`**: 一个包含对所有路由都有效的[片段](#fragment)值的`Observable`对象。 **`outlet`**: The name of the `RouterOutlet` used to render the route. For an unnamed outlet, the outlet name is **primary**. - + **`outlet`**: `RouterOutlet`的名字,用于指示渲染该路由的位置。对于未命名的`RouterOutlet`,这个名字是**primary**。 **`routeConfig`**: The route configuration used for the route that contains the origin path. - + **`routeConfig`**: 与该路由的原始路径对应的配置信息。 **`parent`**: an `ActivatedRoute` that contains the information from the parent route when using [child routes](#child-routing-component). - + **`parent`**: 当使用[子路由](#child-routing-component)时,它是一个包含父路由信息的`ActivatedRoute`对象。 **`firstChild`**: contains the first `ActivatedRoute` in the list of child routes. - + **`firstChild`**: 包含子路由列表中的第一个`ActivatedRoute`对象。 **`children`**: contains all the [child routes](#child-routing-component) activated under the current route. - + **`children`**: 包含当前路由下激活的全部[子路由](#child-routing-component)。 :marked We import the `Router`, `ActivatedRoute`, and `Params` tokens from the router package. - + 我们要从路由器(`router`)包中导入`Router`、`ActivatedRoute`和`Params`类。 +makeExcerpt('app/heroes/hero-detail.component.1.ts (activated route)', 'imports') -a#hero-detail-ctor +:marked + We import the `switchMap` operator because we need it later to process the `Observable` route parameters. ++makeExcerpt('app/heroes/hero-detail.component.1.ts (switchMap operator import)', 'rxjs-operator-import') + +a#hero-detail-ctor :marked As usual, we write a constructor that asks Angular to inject services that the component requires and reference them as private variables. @@ -1660,20 +1629,33 @@ a#hero-detail-ctor +makeExcerpt('app/heroes/hero-detail.component.ts (constructor)', 'ctor') :marked - Later, in the `ngOnInit` method, - we use the `ActivatedRoute` service to retrieve the parameters for our route. - Since our parameters are provided as an `Observable`, we use the _forEach_ method to retrieve them for the `id` parameter by name and - tell the `HeroService` to fetch the hero with that `id`. + Later, in the `ngOnInit` method, we use the `ActivatedRoute` service to retrieve the parameters + for our route. Since our parameters are provided as an `Observable`, we use the _switchMap_ operator to + provide them for the `id` parameter by name and tell the `HeroService` to fetch the hero with that `id`. - 然后,在`ngOnInit`方法中, - 我们用`ActivatedRoute`服务来接收本路由的参数。 + 然后,在`ngOnInit`方法中,我们用`ActivatedRoute`服务来接收本路由的参数。 由于这些参数是作为`Observable`(可观察对象)提供的,所以我们_订阅(`subscribe`)_它们,通过名字引用`id`参数,并告诉`HeroService`获取指定`id`的英雄。 我们还要保存这个`Subscription`(订阅的返回值)的引用,供后面做清理工作。 +makeExcerpt('app/heroes/hero-detail.component.ts (ngOnInit)', 'ngOnInit') .l-sub-section + :marked + The `switchMap` operator allows you to perform an action with the current value of the `Observable`, + and map it to a new `Observable`. As with many `rxjs` operators, `switchMap` handles + an `Observable` as well as a `Promise` to retrieve the value they emit. + `switchMap`允许你在`Observable`的当前值上执行一个动作,并将它映射一个新的`Observable`。像许多其它`rxjs`操作符一样, + `switchMap`既可以处理`Observable`也可以处理`Promise`发射的值。 + + The `switchMap` operator will also cancel any in-flight requests if our user re-navigates to the route + while still retrieving a hero. Our `Observable` is _cold_ until subscribed to, so we use the `subscribe` method + to get and set our retrieved `Hero`. + + 如果用户重新导航到该路由,并且它正在获取一个英雄时,`switchMap`操作符还将取消任何正在执行的请求。`Observable`是一个**冷** + 可观察对象,直接订阅它,所以我们使用`subscribe`方法来获得并设置取到的`英雄`。 + +.l-sub-section :marked Angular calls the `ngOnInit` method shortly after creating an instance of the `HeroDetailComponent`. @@ -1687,7 +1669,6 @@ a#hero-detail-ctor 在后面的[OnInit附录](#onInit)中,我们会再详细讲解这一点。 .l-sub-section - :marked Learn about the `ngOnInit` method in the [Lifecycle Hooks](lifecycle-hooks.html) chapter. @@ -1779,7 +1760,7 @@ h4#snapshot 快照:不需要可观察(no-observable)时的替代方 a#nav-to-list :marked ### Navigating back to the list component - + ### 导航回列表组件 The `HeroDetailComponent` has a "Back" button wired to its `gotoHeroes` method that navigates imperatively @@ -1803,48 +1784,48 @@ a#nav-to-list We use [*route parameters*](#route-parameters) to specify a *required* parameter value *within* the route URL as we do when navigating to the `HeroDetailComponent` in order to view-and-edit the hero with *id:15*. - + 如果想导航到`HeroDetailComponent`以对id为15的英雄进行查看并编辑,就要在路由的URL中使用[*路由参数*](#route-parameters)来指定*必要*参数值。 - + code-example(format="." language="bash"). localhost:3000/hero/15 :marked Sometimes we wish to add *optional* information to a route request. For example, the `HeroListComponent` doesn't need help to display a list of heroes. But it might be nice if the previously-viewed hero were pre-selected when returning from the `HeroDetailComponent`. - + 有时我们希望往路由请求中添加*可选的*信息。 例如,`HeroListComponent`虽然不需要借助此信息显示英雄列表,但是如果从`HeroDetailComponent`返回时,它能自动选中刚刚查看过的英雄就好了。 - + figure.image-display img(src='/resources/images/devguide/router/selected-hero.png' alt="Selected hero") :marked That becomes possible if we can include hero Magneta's `id` in the URL when we return from the `HeroDetailComponent`, a scenario we'll pursue in a moment. - + 如果我们能在从`HeroDetailComponent`返回时在URL中带上英雄Magneta的`id`,不就可以了吗?接下来我们就尝试实现这个场景。 Optional information takes other forms. Search criteria are often loosely structured, e.g., `name='wind*'`. Multiple values are common — `after='12/31/2015' & before='1/1/2017'` — in no particular order — `before='1/1/2017' & after='12/31/2015'` — in a variety of formats — `during='currentYear'` . - + 可选信息有很多种形式。搜索条件通常就不是严格结构化的,比如`name='wind*'`;有多个值也很常见,如`after='12/31/2015'&before='1/1/2017'`; 而且顺序无关,如`before='1/1/2017'&after='12/31/2015'`,还可能有很多种变体格式,如`during='currentYear'`。 These kinds of parameters don't fit easily in a URL *path*. Even if we could define a suitable URL token scheme, doing so greatly complicates the pattern matching required to translate an incoming URL to a named route. - + 这么多种参数要放在URL的*路径*中可不容易。即使我们能制定出一个合适的URL方案,实现起来也太复杂了,得通过模式匹配才能把URL翻译成命名路由。 Optional parameters are the ideal vehicle for conveying arbitrarily complex information during navigation. Optional parameters aren't involved in pattern matching and afford enormous flexibility of expression. - + 可选参数是在导航期间传送任意复杂信息的理想载体。 可选参数不涉及到模式匹配并在表达上提供了巨大的灵活性。 The Router supports navigation with optional parameters as well as required route parameters. We define _optional_ parameters in an *object* after we define our required route parameters. - + 和必要参数一样,路由器也支持通过可选参数导航。 我们在定义完必要参数之后,通过一个*对象*来定义*可选参数*。 @@ -1852,24 +1833,24 @@ figure.image-display ### 路由参数:用必要的还是可选的? There is no hard-and-fast rule. In general, - + 并没有一劳永逸的规则,通常: *prefer a required route parameter when* - + *下列情况下优先使用必要参数* - + * the value is required. * 该值是必须的。 * the value is necessary to distinguish one route path from another. * 该值在区分此路由与其它路由时是必要的。 *prefer an optional parameter when* - + *下列情况下优先使用可选参数* - + * the value is optional, complex, and/or multi-variate. - + * 该值是可选的、复杂的,和/或多变量的。 @@ -1878,7 +1859,7 @@ figure.image-display When navigating to the `HeroDetailComponent` we specified the _required_ `id` of the hero-to-edit in the *route parameter* and made it the second item of the [*link parameters array*](#link-parameters-array). - + 要导航到`HeroDetailComponent`,我们需要在*路由参数*中指定要编辑英雄的必要参数`id`,把这个`id`作为[*链接参数数组*](#link-parameters-array)的第二个条目。 +makeExcerpt('app/heroes/hero-list.component.1.ts', 'link-parameters-array') @@ -1886,7 +1867,7 @@ figure.image-display :marked The router embedded the `id` value in the navigation URL because we had defined it as a route parameter with an `:id` placeholder token in the route `path`: - + 路由器在导航URL中内嵌了`id`的值,这是因为我们把它用一个`:id`占位符当做路由参数定义在了路由的`path`中: +makeExcerpt('app/heroes/heroes-routing.module.ts', 'hero-detail-route') @@ -1894,27 +1875,27 @@ figure.image-display :marked When the user clicks the back button, the `HeroDetailComponent` constructs another *link parameters array* which it uses to navigate back to the `HeroListComponent`. - + 当用户点击后退按钮时,`HeroDetailComponent`构造了另一个*链接参数数组*,可以用它导航回`HeroListComponent`。 +makeExcerpt('app/heroes/hero-detail.component.1.ts', 'gotoHeroes') :marked This array lacks a route parameter because we had no reason to send information to the `HeroListComponent`. - + 该数组缺少一个路由参数,这是因为我们那时没有理由往`HeroListComponent`发送信息。 Now we have a reason. We'd like to send the id of the current hero with the navigation request so that the `HeroListComponent` can highlight that hero in its list. This is a _nice-to-have_ feature; the list will display perfectly well without it. - + 但现在有了。我们要在导航请求中同时发送当前英雄的id,以便`HeroListComponent`可以在列表中高亮这个英雄。 这是一个*有更好,没有也无所谓*的特性,就算没有它,列表照样能显示得很完美。 We do that with an object that contains an _optional_ `id` parameter. For demonstration purposes, we also defined a junk parameter (`foo`) that the `HeroListComponent` should ignore. Here's the revised navigation statement: - + 我们通过一个包含*可选*`id`参数的对象来做到这一点。 为了演示,我们还定义了一个没用的参数(`foo`),`HeroListComponent`应该忽略它。 下面是修改过的导航语句: @@ -1923,39 +1904,39 @@ figure.image-display :marked The application still works. Clicking "back" returns to the hero list view. - + 该应用仍然能工作。点击“back”按钮返回英雄列表视图。 Look at the browser address bar. - + 注意浏览器的地址栏。 - + .l-sub-section img(src='/resources/images/devguide/plunker-separate-window-button.png' alt="pop out the window" align="right" style="margin-right:-20px") :marked When running in plunker, pop out the preview window by clicking the blue 'X' button in the upper right corner. - + 当在plunker中运行时,请点击右上角的蓝色'X'按钮来弹出预览窗口,否则你看不到地址栏的变化。 - + :marked It should look something like this, depending on where you run it: 看起来应该是这样,不过也取决于你在哪里运行它: - + code-example(language="bash"). localhost:3000/heroes;id=15;foo=foo :marked The `id` value appears in the URL as (`;id=15;foo=foo`), not in the URL path. The path for the "Heroes" route doesn't have an `:id` token. - + `id`的值像这样出现在URL中(`;id=15;foo=foo`),但不在URL的路径部分。 “Heroes”路由的路径部分并没有定义`:id`。 The optional route parameters are not separated by "?" and "&" as they would be in the URL query string. They are **separated by semicolons ";"** This is *matrix URL* notation — something we may not have seen before. - + 可选的路由参数没有使用“?”和“&”符号分隔,因为它们将用在URL查询字符串中。 它们是**用“;”分隔的**。 这是*矩阵URL*标记法 —— 我们以前可能从未见过。 @@ -1964,14 +1945,14 @@ code-example(language="bash"). :marked *Matrix URL* notation is an idea first floated in a [1996 proposal](http://www.w3.org/DesignIssues/MatrixURIs.html) by the founder of the web, Tim Berners-Lee. - + *Matrix URL*写法首次提出是在[1996提案](http://www.w3.org/DesignIssues/MatrixURIs.html)中,提出者是Web的奠基人:Tim Berners-Lee。 Although matrix notation never made it into the HTML standard, it is legal and it became popular among browser routing systems as a way to isolate parameters belonging to parent and child routes. The Router is such a system and provides support for the matrix notation across browsers. - + 虽然Matrix写法未曾进入过HTML标准,但它是合法的。而且在浏览器的路由系统中,它作为从父路由和子路由中单独隔离出参数的方式而广受欢迎。Angular的路由器正是这样一个路由系统,并支持跨浏览器的Matrix写法。 The syntax may seem strange to us but users are unlikely to notice or care @@ -1982,11 +1963,11 @@ code-example(language="bash"). :marked ### Route parameters in the *ActivatedRoute* service - + ### *ActivatedRoute*服务中的路由参数 The list of heroes is unchanged. No hero row is highlighted. - + 英雄列表仍没有改变,没有哪个英雄列被加亮显示。 .l-sub-section @@ -1994,51 +1975,66 @@ code-example(language="bash"). The *does* highlight the selected row because it demonstrates the final state of the application which includes the steps we're *about* to cover. At the moment we're describing the state of affairs *prior* to those steps. - + 在线例子*高亮了*选中的行,因为它演示的是应用的最终状态,因此包含了我们*即将*示范的步骤。 此刻,我们描述的仍是那些步骤*之前*的状态。 - + :marked The `HeroListComponent` isn't expecting any parameters at all and wouldn't know what to do with them. Let's change that. - + `HeroListComponent`还完全不需要任何参数,也不知道该怎么处理它们。我们这就改变这一点。 Previously, when navigating from the `HeroListComponent` to the `HeroDetailComponent`, we subscribed to the route params `Observable` and made it available to the `HeroDetailComponent` in the `ActivatedRoute` service. We injected that service in the constructor of the `HeroDetailComponent`. - + 以前,当从`HeroListComponent`导航到`HeroDetailComponent`时,我们通过`ActivatedRoute`服务订阅了路由参数这个`Observable`,并让它能用在`HeroDetailComponent`中。我们把该服务注入到了`HeroDetailComponent`的构造函数中。 This time we'll be navigating in the opposite direction, from the `HeroDetailComponent` to the `HeroListComponent`. - + 这次,我们要进行反向导航,从`HeroDetailComponent`到`HeroListComponent`。 First we extend the router import statement to include the `ActivatedRoute` service symbol; - + 首先,我们扩展该路由的导入语句,以包含进`ActivatedRoute`服务的类; +makeExcerpt('app/heroes/hero-list.component.ts (import)', 'import-router') :marked - Then we use the `ActivatedRoute` to access the `params` _Observable_ so we can subscribe - and extract the `id` parameter as the `selectedId`: - - 然后,使用`ActivatedRoute`来访问`params`这个`Observable`,以便我们订阅它,并把其中的`id`参数提取到`selectedId`中: + We'll import the `switchMap` operator to perform an operation on our `Observable` + of route parameters. -+makeExcerpt('app/heroes/hero-list.component.ts (constructor)', 'ctor') + 我们将导入`switchMap`操作符,在路由参数的`Observable`对象上执行操作。 + ++makeExcerpt('app/heroes/hero-list.component.ts (rxjs imports)', 'rxjs-imports') + +:marked + Then we inject the `ActivatedRoute` in the `HeroListComponent` constructor. + + 接着,我们注入`ActivatedRoute`到`HeroListComponent`的构造函数中。 + ++makeExcerpt('app/heroes/hero-list.component.ts (constructor and ngOnInit)', 'ctor') + +:marked + The ActivatedRoute.params property is an Observable of route parameters. The params emits new id values + when the user navigates to the component. In ngOnInit we subscribe to those values, set the selectedId, + and get the heroes. + + ActivatedRoute.params属性是一个路由参数的可观察对象。当用户导航到这个组件时,params会发射一个新的id值。 + 在ngOnInit中,我们订阅了这些值,设置到selectedId,并获取英雄数据。 .l-sub-section :marked All route/query parameters are strings. The (+) in front of the `params['id']` expression is a JavaScript trick to convert the string to an integer. - + 所有的路由参数或查询参数都是字符串。 `params['id']`表达式前面的加号(+)是一个JavaScript的小技巧,用来把字符串转换成整数。 - + :marked We add an `isSelected` method that returns true when a hero's id matches the selected id. - + 我们添加了一个`isSelected`方法,当英雄的id和选中的id匹配时,它返回真值。 +makeExcerpt('app/heroes/hero-list.component.ts', 'isSelected') @@ -2047,7 +2043,7 @@ code-example(language="bash"). Finally, we update our template with a [Class Binding](template-syntax.html#class-binding) to that `isSelected` method. The binding adds the `selected` CSS class when the method returns `true` and removes it when `false`. Look for it within the repeated `
  • ` tag as shown here: - + 最后,我们用[CSS类绑定](template-syntax.html#class-binding)更新模板,把它绑定到`isSelected`方法上。 如果该方法返回`true`,此绑定就会添加CSS类`selected`,否则就移除它。 在`
  • `标记中找到它,就像这样: @@ -2056,14 +2052,14 @@ code-example(language="bash"). :marked When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected: - + 当用户从英雄列表导航到英雄“Magneta”并返回时,“Magneta”看起来是选中的: - + figure.image-display img(src='/resources/images/devguide/router/selected-hero.png' alt="Selected List" ) :marked The optional `foo` route parameter is harmless and continues to be ignored. - + 这儿可选的`foo`路由参数人畜无害,并继续被忽略。 h3#route-animation Adding animations to the route component @@ -2072,7 +2068,7 @@ h3#route-animation 为路由组件添加动画 Our heroes feature module is almost complete, but what is a feature without some smooth transitions? We already know that Angular supports [animations](../guide/animations.html) and we want to take advantage of them by adding some animation to our *Hero Detail* component. - + 我们的“英雄”这个特性模块就要完成了,但这个特性还没有平滑的专场效果。 我们知道Angular支持[动画](../guide/animations.html),想要得到这项优点,就要为*英雄详情*组件添加一些动画。 @@ -2080,7 +2076,7 @@ h3#route-animation 为路由组件添加动画 control state and manage transitions between states. We'll use these functions to add transitions to our route component as it moves between states our application view. We'll also import the `HostBinding` decorator for binding to our route component. - + 首先,我们从导入动画函数开始,它们用于构建动画触发器,以控制状态和管理状态之间的转场。 我们使用这些函数来把转场效果添加到路由组件中,这样当应用视图的多个状态之间发生转移时,就会触发动画。 我们还要导入`HostBinding`装饰器来绑定到路由组件。 @@ -2092,13 +2088,12 @@ h3#route-animation 为路由组件添加动画 about the choice of the binding name, but since we are controlling route animation, we'll go with `routeAnimation`. The binding value is set to `true` because we only care about the `:enter` and `:leave` states which are [entering and leaving](../api/core/index/transition-function.html#transition-aliases-enter-and-leave-) transition aliases. - + 接下来,我们将对名叫`@routeAnimation`的路由动画使用**宿主绑定(HostBinding)**。选择绑定名时没什么特别的要求,但是由于我们是在控制路由的动画,所以把它叫做`routeAnimation`。 该绑定值被设置为`true`,因为我们只关心`:enter`和`:leave`状态,这些动画状态代表[进场和离开](../api/core/index/transition-function.html#transition-aliases-enter-and-leave-)。 - We'll also add some display and positioning bindings for styling. - + 我们还将为样式添加一些显示和位置绑定。 +makeExcerpt('app/heroes/hero-detail.component.ts (route animation binding)', 'route-animation-host-binding') @@ -2108,28 +2103,27 @@ h3#route-animation 为路由组件添加动画 setup. We'll use the **wildcard state** that matches any animation state our route component is in, along with two *transitions*. One transition animates the component as it enters the application view (`:enter`), while the other animates the component as it leaves the application view (`:leave`). - + 现在,我们可以构建动画触发器了,我们称之为*routeAnimation*来匹配我们以前定义的绑定。 我们的使用**通配符状态**,它们匹配我们这个路由组件的任意动画状态, 后面是两个*转场动画*。一个转场动画(`:enter`)在组件进入应用视图时触发, 另一个(`:leave`)在离开时触发。 - We could add different transitions to different route components depending on our needs. We'll just animate our `HeroDetailComponent` for this milestone. - + 如果需要,我们还可以为其它路由组件添加不同的转场动画。在这个里程碑中我们只为`HeroDetailComponent`添加动画。 .l-sub-section :marked Using route animations on individual components is something we don't want to do throughout our entire application. It would be better to animate routes based on **route paths**, a topic to cover in a future update to this chapter. - + 在整个应用程序中,我们并不想在每个组件中都使用路由动画。 我们认为基于**路由路径**进行路由动画会更好一些,本章将来的更新中会涉及到这个主题。 :marked Our route component animation looks as such: - + 我们的路由动画看起来像这样: +makeExcerpt('app/heroes/hero-detail.component.ts (route animation)', 'route-animation') @@ -2137,7 +2131,7 @@ h3#route-animation 为路由组件添加动画 :marked Simply stated, our `HeroDetailComponent` will ease in from the left when routed to and will slide down when navigating away. We could add more complex animations here, but we'll leave our `HeroDetailComponent` as is for now. - + 简单的说,当进入路由时,`HerodetailComponent`组件会从左侧弹入,离开时会向下方滑出。 这里我们还可以添加更复杂的动画,不过我们现在就先不这么做了。 @@ -2151,20 +2145,20 @@ h3#merge-hero-routes 把hero模块导入到AppModule中 我们得把它导入我们在`app.module.ts`中导入的`AppModule`中。 Update `app.module.ts` as follows: - + 像这样修改`app.module.ts`: +makeExcerpt('app/app.module.3.ts (heroes module import)', 'hero-import') :marked We imported the `HeroesModule` and added it to our `AppModule`'s `imports`. - + 我们导入了`HeroesModule`,并把它加入了`AppModule`的`imports`中。 We removed the `HeroListComponent` from the `AppModule`'s `declarations` because its being provided by the `HeroesModule` now. This is important because there can be only **one** owner for a declared component. In our case, the `Heroes` module is the owner of the `Heroes` components and is making them available to the `AppModule`. - + 我们从`AppModule`的`declarations`中移除了`HeroListComponent`,因为它现在改有`HeroesModule`提供了。 这一步很重要,因为一个组件只能有**一个**所有者。现在这种情况下,`Heroes`模块应该是`Heroes`组件的所有者,并让它可用于`AppModule`中。 @@ -2173,22 +2167,21 @@ h3#merge-hero-routes 把hero模块导入到AppModule中 Routes provided by feature modules will be combined together into their imported module's routes by the router. This allows us to continue defining our feature module routes without modifying our main route configuration. - + 由特性模块提供的路由将会被路由器和它们导入的模块提供的路由组合在一起。这让我们可以继续定义特性路由,而不用修改主路由配置。 :marked As a result, the `AppModule` no longer has specific knowledge of the hero feature, its components, or its route details. We can evolve the hero feature with more components and different routes. That's a key benefit of creating a separate module for each feature area. - + 这种调整的结果是:`app.module.ts`不再具有任何有关英雄特性的特殊知识,关于它的组件或路由的细节。 这个“英雄特性区”可以演化出更多的组件和不同的路由。 这是为每个特性区创建一个独立模块带来的核心优势。 Since our `Heroes` routes are defined within our feature module, we can also remove our initial `heroes` route from the `app-routing.module.ts`. - + 由于`Heroes`路由被定义在了我们的特性模块中,我们也可以从`app-routing.module.ts`中移除当初的`heroes`路由了。 - +makeExcerpt('app/app-routing.module.2.ts (v2)', '') @@ -2218,9 +2211,9 @@ h3#merge-hero-routes 把hero模块导入到AppModule中 * 通过路由参数传递信息,并在组件中订阅它们。 * import our feature area NgModule into our `AppModule` - + * 在`AppModule`中导入特征区的`NgModule`。 - + * apply animations to our route component * 把动画应用到路由组件上 @@ -2302,11 +2295,9 @@ h3#merge-hero-routes 把hero模块导入到AppModule中 When the user selects a crisis, the app navigates to the `CrisisDetailComponent` for display and editing of the crisis name. - `Crisis`有一个`id`和一个`name`,就像`Hero`一样。新的`CrisisListComponent`显示危机列表。如果用户选择了一个危机,该应用就会导航到`CrisisDetailComponent`,用于显示和编辑危机的名字。 + Voilà, another feature module! - Voila, another feature module! - - 真棒!另一个特性模块诞生了! + 真棒!另一个特性模块诞生了 There's no point to this exercise unless we can learn something. We do have new ideas and techniques in mind: @@ -2334,6 +2325,13 @@ h3#merge-hero-routes 把hero模块导入到AppModule中 * 如果用户尚未登录,路由器就应该阻止它访问某些特性。 + * Changes to a feature module such as *Crisis Center* shouldn't provoke changes to the `AppModule` or + any other feature's component. + We need to [*separate our concerns*](https://blog.8thlight.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html). + + * 对特性模块(如*Crisis Center*)的修改不应引起`AppModule`或其它特性模块的组件的修改。 + 我们需要[*隔离我们的关注*](https://blog.8thlight.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html). + We'll address all of these issues in the *Crisis Center* starting with the introduction of **child routes** @@ -2383,7 +2381,7 @@ figure.image-display a#child-routing-component :marked ### Child Routing Component - + ### 子路由组件 Add the following `crisis-center.component.ts` to the `crisis-center` folder: @@ -2441,9 +2439,9 @@ a#child-routing-component 它有自己的`RouterOutlet`和自己的子路由。 Add the following `crisis-center-home.component.ts` to the `crisis-center` folder. - + 把下面的`crisis-center-home.component.ts`文件添加到`crisis-center`目录中。 - + +makeExcerpt('app/crisis-center/crisis-center-home.component.ts (minus imports)', 'minus-imports') :marked @@ -2462,7 +2460,7 @@ a#child-routing-component 注意,父路由`crisis-center`有一个`children`属性,它有一个包含`CrisisListComponent`的路由。 `CrisisListModule`路由还有一个带两个路由的`children`数组。 - + These two routes navigate to the two *Crisis Center* child components, `CrisisCenterHomeComponent` and `CrisisDetailComponent`. @@ -2479,45 +2477,45 @@ a#child-routing-component The `CrisisListComponent` contains the crisis list and a `RouterOutlet` to display the `Crisis Center Home` and `Crisis Detail` route components. - + `CrisisListComponent`包含危机列表和一个`RouterOutlet`,用以显示`Crisis Center Home`和`Crisis Detail`这两个路由组件。 - + The `Crisis Detail` route is a child of the `Crisis List`. Since the router [reuses components](#reuse) by default, the `Crisis Detail` component will be re-used as we select different crises. - + `Crisis Detail`路由是`Crisis List`的子路由。由于路由器默认会[复用组件](#reuse),因此当我们选择了另一个危机时,`CrisisDetailComponent`会被复用。 - + In contrast, back in the `Hero Detail` route, the component was recreated each time we selected a different hero. - + 作为对比,回到`Hero Detail`路由时,每当我们选择了不同的英雄时,该组件都会被重新创建。 - + At the top level, paths that begin with `/` refer to the root of the application. But these are child routes. They *extend* the path of the parent route. With each step down the route tree, we add a slash followed by the route path (unless the route path is _empty_). - + 在顶级,以`/`开头的路径指向的总是应用的根。 但这里是子路由。 它们是在父路由路径的基础上做出的扩展。 在路由树中每深入一步,我们就会在该路由的路径上添加一个斜线`/`(除非该路由的路径是*空的*)。 - + For example, the parent path to the `CrisisCenterComponent` is `/crisis-center` The router appends these child paths to the parent path to the `CrisisCenterComponent` (`/crisis-center`). - + 例如,`CrisisCenterComponent`的路径是`/crisis-center`。 路由器就会把这些子路由的路径中添加上到父路由`CrisisCenterComponent`的路径(`/crisis-center`)。 - + * to navigate to the `CrisisCenterHomeComponent`, the full URL is `/crisis-center` (`/crisis-center` + `''` + `''`). - + * 要导航到`CrisisCenterHomeComponent`,完整的URL是`/crisis-center` (`/crisis-center` + `''` + `''`)。 - + * to navigate to the `CrisisDetailComponent` for a crisis with `id=2`, the full URL is `/crisis-center/2` (`/crisis-center` + `''` + `'/2'`). - + * 要导航到`CrisisDetailComponent`以展示`id=2`的危机,完整的URL是`/crisis-center/2` (`/crisis-center` + `''` + `'/2'`)。 - + The absolute URL for the latter example, including the origin, is - + 本例子中的绝对URL,包含源站部分,就是: code-example. @@ -2536,16 +2534,16 @@ h3#import-crisis-module 把危机中心模块导入`AppModule`的路由中 :marked As with the `Heroes` module, we must import the `Crisis Center` module into the `AppModule`: - + 像`Heroes`模块中一样,我们必须把`危机中心`模块导入`AppModule`中: - + +makeExcerpt('app/app.module.4.ts (import CrisisCenterModule)', 'crisis-center-module') :marked We also remove the initial crisis center route from our `app-routing.module.ts`. Our routes are now being provided by our `HeroesModule` and our `CrisisCenter` feature modules. We'll keep our `app-routing.module.ts` file for general routes which we'll cover later in the chapter. - + 我们还从`app.routing.ts`中移除了危机中心的初始路由。我们的路由现在是由`HeroesModule`和`CrisisCenter`特性模块提供的。 我们将保持`app.routing.ts`文件中只有通用路由,本章稍后会讲解它。 @@ -2555,7 +2553,7 @@ a#redirect :marked ### Redirecting routes - + ### 重定向路由 When the application launches, the initial URL in the browser bar is something like: @@ -2574,14 +2572,14 @@ code-example. We prefer that the application display the list of crises as it would if the user clicked the "Crisis Center" link or pasted `localhost:3000/crisis-center/` into the address bar. This is our intended default route. - + 当用户点击了“Crisis Center”链接或者在地址栏粘贴`localhost:3000/crisis-center/`时,我们更希望该应用能直接显示危机列表。这就是默认路由。 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`)。 - + +makeExcerpt('app/crisis-center/crisis-center-routing.module.2.ts' , 'redirect', '') :marked @@ -2591,37 +2589,37 @@ code-example. “重定向(redirect)路由”需要一个`pathMatch`属性来告诉路由器如何把URL和路由中的路径进行匹配。 本应用中,路由器应该只有在*完整的URL*匹配`''`时才选择指向`CrisisListComponent`的路由,因此,我们把`pathMatch`的值设置为`'full'`。 - + .l-sub-section :marked 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. - + 从原理上说,`pathMatch = 'full'`导致路由器尝试用URL中*剩下的*、未匹配过的片段去匹配`''`。 在这个例子中,重定向发生在路由配置树的顶级,所以*剩下的*URL和*完整的*URL是完全一样的。 - + 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. - + `pathMatch`的另一个可能的值是`'prefix'`,这会告诉路由器去匹配*剩下的*URL是否以这个“重定向路由”的*前缀*路径***开头***。 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`. - + 显然,在这里我们并不想这样。如果`pathMatch`的值是`'prefix'`,_每个_URL都会匹配`''`。 因为这个“重定向路由”会首先匹配上并把我们引向`CrisisListComponent`,所以我们就永远无法导航到`/crisis-center/1`了。 We should redirect to the `CrisisListComponent` _only_ when the _entire (remaining)_ url is `''`. - + _只有_当_完整的(剩余的)_URL是`''`时,我们才应该重定向到`CrisisListComponent`。 Learn more in Victor Savkin's blog [post on redirects](http://victorsavkin.com/post/146722301646/angular-router-empty-paths-componentless-routes). - + 要学习更多,请参见Victor Savkin的博客中 [关于重定向的帖子](http://victorsavkin.com/post/146722301646/angular-router-empty-paths-componentless-routes). @@ -2645,21 +2643,21 @@ h2#relative-navigation 相对导航 *Crisis Detail* route using an **absolute path** that begins with a **slash**. This navigation starts from the top of our route configuration to find the matching path to our route. - + 当构建*危机中心*特性时,我们将使用以**斜线**开头的**绝对路径**来导航到*危机详情*路由。 这次导航会从路由配置的顶部开始查找路由,以匹配路径。 We could continue to use absolute paths to navigate inside our *Crisis Center* feature, but that makes our links very rigid. If we changed our parent `/crisis-center` path, we would have to change our link parameters array. - + 我们可以在*危机中心*特性区继续使用绝对路径进行导航,但这会让我们的链接过于死板。 如果更改了父路由路径`/crisis-center`,我们就不得不到处更改链接参数数组。 We can make our links more flexible by using **relative** navigation with the router. - + 通过让路由器使用**相对**导航的方式,我们可以让链接更富有弹性。 - + * The full path to the route is not required. * 不再需要到路由的完整路径。 * Navigation within our feature area remains intact if the parent route path is changed. @@ -2670,21 +2668,21 @@ h2#relative-navigation 相对导航 .l-sub-section :marked The **link parameters array** supports a directory-like syntax for relative navigation. - + **链接参数数组**通过目录式语法支持相对导航。 `./` or `no leading slash` is relative to the current level. - + `./`或“无前导斜线”时表示相当于当前级别。 `../` to go up one level in the route path. - + `../`表示在路由路径中往上走一级。 The relative navigation syntax can be used in combination with a *path*. If we wanted to navigate from one route path to another sibling route path we could use `../path` convention to go up one level and down to the sibling route path. - + 相对导航的语法可以和*路径*组合在一起,如果我们要从一个路由路径导航到一个兄弟路由路径, 可以使用`../path`来简便的导航到上一级然后再进入兄弟路由路径。 @@ -2695,7 +2693,7 @@ h2#relative-navigation 相对导航 `router.navigate` method after the *link parameters array* specifying the **relativeTo** property. We set the `relativeTo` property to our `ActivatedRoute` and the router will merge our navigation information into to the current URL. - + 要使用`Router`进行相对导航,可以使用`ActivatedRoute`来告诉路由器我们正在*RouterState*中的什么地方,*RouterState*是激活路由组成的树。 要做到这一点,我们可以为`router.navigate`方法中*链接参数数组*后的对象型参数指定**relativeTo**属性。 只要把这个`relativeTo`属性设置为我们的`ActivatedRoute`,路由器就会把我们的导航信息和当前URL合并在一起。 @@ -2703,18 +2701,18 @@ h2#relative-navigation 相对导航 .l-sub-section :marked When using router's `navigateByUrl` method, the navigation is **always** absolute. - + 当使用路由器的`navigateByUrl`方法时,导航**总是**绝对的。 :marked ### Navigate to Crisis Detail relatively - + ### 用相对方式导航到危机详情 Let's update our *Crisis List* `onSelect` method to use relative navigation so we don't have to start from the top of our route configuration. We've already injected the `ActivatedRoute` into our constructor that we'll need for the relative navigation. - + 我们来把*危机列表*中的`onSelect`方法改成相对导航,以便我们不必从路由配置的顶部开始。 我们已经把相对导航所需的`ActivatedRoute`注入到了构造函数中。 @@ -2724,7 +2722,7 @@ h2#relative-navigation 相对导航 When we visit the *Crisis Center*, our path is `/crisis-center`, so we just want to add the `id` of the *Crisis Center* to our existing path. When the router navigates, it will use the current path `/crisis-center`, adding on our `id`. If our `id` were `1`, the resulting path would be `/crisis-center/1`. - + 当我们访问*危机中心*时,当前路径是`/crisis-center`,所以我们只要把*危机*的`id`添加到现有路径中就可以了。当路由器导航时,它使用当前路径`/crisis-center`并追加上此`id`。如果`id`为`1`,结果路径就是`/crisis-center/1`。 +makeExcerpt('app/crisis-center/crisis-list.component.ts (relative navigation)', 'relative-navigation') @@ -2733,7 +2731,7 @@ h2#relative-navigation 相对导航 We'll also update the *Crisis Detail* component to navigate back to our *Crisis Center* list. We want to go back up a level in the path, so we use to the `../` syntax. If our current `id` is `1`, the resulting path coming from `/crisis-center/1` would be `/crisis-center`. - + 我们还要修改*危机详情*组件以便导航回*危机中心*列表。我们得回到路径的上一级,所以我们使用`../`语法。如果当前`id`是`1`,那么结果路径就会从`/crisis-center/1`变成`/crisis-center`。 +makeExcerpt('app/crisis-center/crisis-detail.component.1.ts (relative navigation)', 'relative-navigation') @@ -2742,7 +2740,7 @@ h2#relative-navigation 相对导航 If we are using a `RouterLink` to navigate instead of the `Router` service, we can use the **same** link parameters array, but we don't have to provide the object with the `relativeTo` property. The `ActivatedRoute` is implicit in the `RouterLink` directive. - + 如果我们正在使用`RouterLink`进行导航,而不是`Router`服务,仍然可以使用**相同的**链接参数数组,不过我们不用提供带`relativeTo`属性的对象。在`RouterLink`指令中`ActivatedRoute`是默认的。 +makeExcerpt('app/crisis-center/crisis-list.component.1.ts (relative routerLink)', 'relative-navigation-router-link') @@ -2829,21 +2827,21 @@ h2#guards 路由守卫 1. [CanActivate](../api/router/index/CanActivate-interface.html) to mediate navigation *to* a route. 1. 用[CanActivate](../api/router/index/CanActivate-interface.html)来处理导航*到*某路由的情况。 - + 2. [CanActivateChild](../api/router/index/CanActivateChild-interface.html) to mediate navigation *to* a child route. - + 2. 用[CanActivateChild](../api/router/index/CanActivateChild-interface.html)处理导航*到*子路由的情况。 - + 3. [CanDeactivate](../api/router/index/CanDeactivate-interface.html) to mediate navigation *away* from the current route. 3. 用[CanDeactivate](../api/router/index/CanDeactivate-interface.html)来处理从当前路由*离开*的情况。 - + 4. [Resolve](../api/router/index/Resolve-interface.html) to perform route data retrieval *before* route activation. - + 4. 用[Resolve](../api/router/index/Resolve-interface.html)在路由激活*之前*获取路由数据。 - + 5. [CanLoad](../api/router/index/CanLoad-interface.html) to mediate navigation *to* a feature module loaded _asynchronously_. - + 5. 用[CanLoad](../api/router/index/CanLoad-interface.html)来处理*异步*导航到某特性模块的情况。 :marked @@ -2860,13 +2858,13 @@ h2#guards 路由守卫 如果_任何_守卫返回`false`,其它尚未完成的守卫会被取消,这样整个导航就被取消了。 Let's look at some examples. - + 我们来看一些例子。 a#can-activate-guard :marked ### *CanActivate*: requiring authentication - + ### *CanActivate*: 要求认证 Applications often restrict access to a feature area based on who the user is. @@ -2894,7 +2892,7 @@ a#can-activate-guard 我们会遵循与创建`admin`目录中的特性模块文件、路由文件和支持组件时相同的约定。 Our admin feature module file structure looks like this: - + 管理特性区的文件是这样的: .filetree @@ -2910,7 +2908,7 @@ a#can-activate-guard :marked Our admin feature module contains our `AdminComponent` used for routing within our feature module, a dashboard route and two unfinished components to manage crises and heroes. - + 管理特性模块包含`AdminComponent`,它用于在特性模块内的仪表盘路由以及两个尚未完成的用于管理危机和英雄的组件之间进行路由。 +makeTabs( @@ -2935,12 +2933,12 @@ a#can-activate-guard link to be active when we visit that route. We've added an additional binding to our `Dashboard` routerLink, `[routerLinkActiveOptions]="{ exact: true }"` which will only mark the `./` link as active when we navigate the to `/admin` URL and not when we navigate to one the other child routes. - + 由于`AdminModule`中管理仪表盘的`RouterLink`是一个空路径的路由,所以它会匹配到管理特性区的任何路由。但我们只有在访问`Dashboard`路由时才希望该链接被激活。所以我们往`Dashboard`这个routerLink上添加了另一个绑定`[routerLinkActiveOptions]="{ exact: true }"`,这样就只有当我们导航到`/admin`这个URL时才会激活它,而不会在导航到它的某个子路由时。 :marked Our initial admin routing configuration: - + 我们的初始管理路由配置如下: +makeExcerpt('app/admin/admin-routing.module.1.ts (admin routing)', 'admin-routes') @@ -2951,7 +2949,7 @@ h3#component-less-route 无组件路由: 不借助组件对路由进行 Looking at our child route under the `AdminComponent`, we have a route with a **path** and a **children** property but it's not using a **component**. We haven't made a mistake in our configuration, because we can use a **component-less** route. - + 来看`AdminComponent`下的子路由,我们有一个带**path**和**children**的子路由,但它没有使用**component**。这并不是配置中的失误,而是在使用**无组件**路由。 We want to group our `Crisis Center` management routes under the `admin` path, but we don't need a component @@ -2959,11 +2957,11 @@ h3#component-less-route 无组件路由: 不借助组件对路由进行 虽然我们希望对`admin`路径下的`危机中心`管理类路由进行分组,但并不需要另一个仅用来分组路由的组件。 这同时也允许我们[守卫子路由](#can-activate-child-guard)。 - + :marked Next, we'll import the `AdminModule` into our `app.module.ts` and add it to the `imports` array to register our admin routes. - + 接下来,我们把`AdminModule`导入到`app.module.ts`中,并把它加入`imports`数组中来注册这些管理类路由。 +makeExcerpt('app/app.module.4.ts (admin module)', 'admin-module') @@ -3061,17 +3059,17 @@ h3#component-less-route 无组件路由: 不借助组件对路由进行 If the user is logged in, it returns true and the navigation continues. 该守卫返回一个同步的布尔值。如果用户已经登录,它就返回`true`,导航会继续。 - + The `ActivatedRouteSnapshot` contains the _future_ route that will be activated and the `RouterStateSnapshot` contains the _future_ `RouterState` of our application, should we pass through our guard check. - + 这个`ActivatedRouteSnapshot`包含了_即将_被激活的路由,而`RouterStateSnapshot`包含了该应用_即将_到达的状态。 它们要通过我们的守卫进行检查。 If the user is not logged in, we store the attempted URL the user came from using the `RouterStateSnapshot.url` and tell the router to navigate to a login page — a page we haven't created yet. This secondary navigation automatically cancels the current navigation; we return `false` just to be clear about that. - + 如果用户还没有登录,我们会用`RouterStateSnapshot.url`保存用户来自的URL并让路由器导航到登录页(我们尚未创建该页)。 这间接导致路由器自动中止了这次导航,我们返回`false`并不是必须的,但这样可以更清楚的表达意图。 @@ -3086,7 +3084,6 @@ h3#component-less-route 无组件路由: 不借助组件对路由进行 我们需要一个`LoginComponent`来让用户登录进这个应用。在登录之后,我们跳转到前面保存的URL,如果没有,就跳转到默认URL。 该组件没有什么新内容,我们把它放进路由配置的方式也没什么新意。 - We'll register a `/login` route in our `login-routing.module.ts` and add the necessary providers to the `providers` array. In our `app.module.ts`, we'll import the `LoginComponent` and add it to our `AppModule` `declarations`. We'll also import and add the `LoginRoutingModule` to our `AppModule` imports. @@ -3094,7 +3091,7 @@ h3#component-less-route 无组件路由: 不借助组件对路由进行 我们将在`login-routing.module.ts`中注册一个`/login`路由,并把必要的提供商添加`providers`数组中。 在`app.module.ts`中,我们导入`LoginComponent`并把它加入根模块的`declarations`中。 同时在`AppModule`中导入并添加`LoginRoutingModule`。 - + +makeTabs( `router/ts/app/app.module.ts, router/ts/app/login.component.1.ts, @@ -3111,7 +3108,7 @@ h3#component-less-route 无组件路由: 不借助组件对路由进行 Guards and the service providers they require **must** be provided at the module-level. This allows the Router access to retrieve these services from the `Injector` during the navigation process. The same rule applies for feature modules loaded [asynchronously](#asynchronous-routing). - + 它们所需的守卫和服务提供商**必须**在模块一级提供。这让路由器在导航过程中可以通过`Injector`来取得这些服务。 同样的规则也适用于[异步加载](#asynchronous-routing)的特性模块。 @@ -3122,7 +3119,7 @@ h3#can-activate-child-guard CanActivateChild: 守卫子路由 guard. The `CanActivateChild` guard works similarly to the `CanActivate` guard, but the difference is its run _before_ each child route is activated. We protected our admin feature module from unauthorized access, but we could also protect child routes within our feature module. - + 就像我们可以通过`CanActivate`来守卫路由一样,我们也能通过`CanActivateChild`守卫来保护子路由。`CanActivateChild`守卫的工作方式和`CanActivate`守卫很相似,不同之处在于它会在每个子路由被激活*之前*运行。我们保护了管理特性模块不受未授权访问,也同样可以在特性模块中保护子路由。 Let's extend our `AuthGuard` to protect when navigating between our `admin` routes. First we'll open our @@ -3133,8 +3130,8 @@ h3#can-activate-child-guard CanActivateChild: 守卫子路由 Next, we'll implement the `canActivateChild` method with takes the same arguments as the `canActivate` method, an `ActivatedRouteSnapshot` and `RouterStateSnapshot`. The `canActivateChild` behaves the same way the other guards do, returning an `Observable` or `Promise` for async checks and `boolean` for sync checks. - We'll return a `boolean`: - + We'll return a `boolean` + 然后,我们实现`canActivateChild`方法,它接收与`canActivate`方法相同的参数:`ActivatedRouteSnapshot`和`RouterStateSnapshot`。 `canActivateChild`和其它守卫的行为一样,都返回`Observable`或`Promise`以支持异步检查,或返回`boolean`来支持同步检查。 这里我们直接返回`boolean`: @@ -3144,7 +3141,7 @@ h3#can-activate-child-guard CanActivateChild: 守卫子路由 :marked We add the same `AuthGuard` to our `component-less` admin route to protect all other child routes at one time instead of adding the `AuthGuard` to each route individually. - + 我们往“无组件”的管理路由中添加同一个`AuthGuard`以同时保护所有子路由,而不是挨个添加它们。 +makeExcerpt('app/admin/admin-routing.module.3.ts (excerpt)', 'can-activate-child') @@ -3280,7 +3277,7 @@ a#CanDeactivate Looking back at our `CrisisDetailComponent`, we have implemented our confirmation workflow for unsaved changes. 看看`CrisisDetailComponent`组件,我们已经实现了对未保存的更改进行确认的工作流。 - + +makeExcerpt('app/crisis-center/crisis-detail.component.1.ts (excerpt)', 'cancel-save-only') :marked @@ -3302,7 +3299,7 @@ a#CanDeactivate We also need to add the `Guard` to our main `AppRoutingModule` `providers` so the `Router` can inject it during the navigation process. 我们还要把这个`Guard`添加到`appRoutingModule`的`providers`中去,以便`Router`可以在导航过程中注入它。 - + +makeExample('app/app-routing.module.4.ts', '', '') :marked @@ -3317,7 +3314,7 @@ h3#resolve-guard 解析: 提前获取组件数据 In our `Hero Detail` and `Crisis Detail`, we waited until the route was activated to fetch our respective hero or crisis. 在`Hero Detail`和`Crisis Detail`中,它们等待路由读取对应的英雄和危机。 - + This worked well for us, but we can always do better. If we were using a real world api, there may be some delay in when the data we want to display gets returned. We don't want to display a blank component until the data loads in this situation. @@ -3463,14 +3460,13 @@ a#query-parameters a#fragment :marked ### Query Parameters and Fragments - + ### 查询参数及片段 - -:marked + In our [route parameters](#optional-route-parameters) example, we only dealt with parameters specific to our route, but what if we wanted optional parameters available to all routes? This is where our query parameters come into play and serve a special purpose in our application. - + 在这个[查询参数](#query-parameters)例子中,我们只为路由指定了参数,但是该如何定义一些所有路由中都可用的可选参数呢? 要达到这个目的,该“查询参数”大显身手了。 @@ -3480,15 +3476,15 @@ a#fragment [片段](https://en.wikipedia.org/wiki/Fragment_identifier)可以引用页面中带有特定`id`属性的元素. We'll update our `AuthGuard` to provide a `session_id` query that will remain after navigating to another route. - + 接下来,我们将更新`AuthGuard`来提供`session_id`查询参数,在导航到其它路由后,它还会存在。 We'll also provide an arbitrary `anchor` fragment, which we would use to jump to a certain point on our page. - + 我们还将随意提供一个锚点片段,它用来跳转到页面中指定的位置。 We'll add the `NavigationExtras` object to our `router.navigate` method that navigates us to our `/login` route. - + 我们还将为`router.nativate`方法传入一个`NavigationExtras`对象,用来导航到`/login`路由。 +makeExcerpt('app/auth-guard.service.4.ts (v3)', '') @@ -3506,7 +3502,7 @@ a#fragment :marked Since we'll be navigating to our *Admin Dashboard* route after logging in, we'll update it to handle our query parameters and fragment. - + 由于要在登录后导航到*危机管理*特征区的路由,所以我们还得更新它,来处理这些全局查询参数和片段。 +makeExcerpt('app/admin/admin-dashboard.component.2.ts (v2)', '') @@ -3516,17 +3512,17 @@ a#fragment Just like our *route parameters*, query parameters and fragments are provided as an `Observable`. For our updated *Crisis Admin* component we'll feed the `Observable` directly into our template using the `AsyncPipe`, which will handle _unsubscribing_ from the `Observable` for us when the component is destroyed. - + *查询参数*和*片段*可通过`Router`服务的`routerState`属性使用。和*路由参数*类似,全局查询参数和片段也是`Observable`对象。 在更新过的*英雄管理*组件中,我们将直接把`Observable`传给模板,借助`AsyncPipe`在组件被销毁时自动_取消_对`Observable`的订阅。 .l-sub-section - + img(src='/resources/images/devguide/plunker-separate-window-button.png' alt="pop out the window" align="right" style="margin-right:-20px") - + :marked When running in plunker, pop out the preview window by clicking the blue 'X' button in the upper right corner. - + 当在plunker中运行时,可以点击右上角的蓝色'X'按钮来弹出预览窗口。 :marked @@ -3535,7 +3531,7 @@ a#fragment we have been redirected to the `Admin Dashboard` page with our `query params` and `fragment` still intact. We can use these persistent bits of information for things that need to be provided with across pages interaction like authentication tokens or session ids. - + 按照下列步骤试验下:点击*Crisis Admin*按钮,它会带着我们提供的“查询参数”和“片段”跳转到登录页。 点击登录按钮,我们就会被带到`Crisis Admin`页,仍然带着上一步提供的“查询参数”和“片段”。 我们可以用这些持久化信息来携带需要为每个页面都提供的信息,如认证令牌或会话的ID等。 @@ -3544,7 +3540,7 @@ a#fragment :marked The `query params` and `fragment` can also be preserved using a `RouterLink` with the **preserveQueryParams** and **preserveFragment** bindings respectively. - + “查询参数”和“片段”也可以分别用`RouterLink`中的**preserveQueryParams**和**preserveFragment**保存。 @@ -3592,7 +3588,7 @@ a#fragment We'll start by adding an `admin` route to our `app-routing.module.ts` file. We want to load our `Admin` module asynchronously, so we'll use the `loadChildren` property in our route config where previously we used the `children` property to include our child routes. - + 首先,把`admin`路由添加到 `app-routing.module.ts`文件中。我们想要异步加载`Admin`模块, 就得在路由配置中使用`loadChildren`属性,而以前我们已经用`children`属性包含进了这些子路由。 @@ -3613,13 +3609,13 @@ a#fragment :marked The `loadChildren` property is used by the `Router` to map to our bundle we want to lazy-load, in this case being the `AdminModule`. - + 路由器用`loadChildren`属性来映射我们希望惰性加载的捆文件,这里是`AdminModule`。 If we look closer at the `loadChildren` string, we can see that it maps directly to our `admin.module.ts` file where we previously built out our `Admin` feature area. After the path to the file we use a `#` to denote where our file path ends and to tell the `Router` the name of our `AdminModule`. If we look in our `admin.module.ts` file, we can see it matches name of our exported module class. - + 仔细看`loadChildren`字符串,就会发现它直接映射到了我们以前在管理特性区构建的`admin.module.ts`文件。在文件路径后面,我们使用`#`来标记出文件路径的末尾,并告诉路由器`AdminModule`的名字。打开`admin.module.ts`文件,我们就会看到它正是我们所导出的模块类的名字。 +makeExcerpt('app/admin/admin.module.ts (export)', 'admin-module-export') @@ -3629,7 +3625,7 @@ a#fragment The router will take our loadChildren string and dynamically load in our `AdminModule`, add its routes to our configuration *dynamically* and then load the requested route. This will only happen when the route is **first** requested and the module will be immediately be available for subsequent requests. - + 路由器用`loadChildren`属性来映射我们希望惰性加载的捆文件,这里是`AdminModule`。路由器将接收我们的`loadChildren`字符串,并把它动态加载进`AdminModule`,它的路由被*动态*合并到我们的配置中,然后加载所请求的路由。但只有在首次加载该路由时才会这样做,后续的请求都会立即完成。 .l-sub-section @@ -3645,7 +3641,7 @@ a#fragment `imports` array since we'll be loading it on-demand an we'll remove the imported `AdminModule`. 我们构建了特性区,更新了路由配置来实现惰性加载,现在该做最后一步:将`AdminModule`分离到一个彻底独立的模块。因为现在按需加载`AdminModule`,所以在`app.module.ts`中,从`imports`数组中删除它。 - + +makeExcerpt('app/app.module.7.ts (async admin module)', '') h3#can-load-guard CanLoad Guard: guarding against loading of feature modules @@ -3656,23 +3652,23 @@ h3#can-load-guard CanLoad守卫: 保护特性模块的加载 asynchronously when requested, checking the user access and redirecting to the login page if not authorized. Ideally, we only want to load the `AdminModule` if the user is logged in and prevent the `AdminModule` and its routing from being loaded until then. - + 我们已经使用`CanAcitvate`保护`AdminModule`了,它会阻止对管理特性区的匿名访问。我们在请求时可以异步加载管理类路由,检查用户的访问权,如果用户未登录,则跳转到登陆页面。但更理想的是,我们只在用户已经登录的情况下加载`AdminModule`,并且直到加载完才放行到它的路由。 The **CanLoad** guard covers this scenario. - + **CanLoad**守卫适用于这个场景。 We can use the `CanLoad` guard to only load the `AdminModule` once the user is logged in **and** attempts to access the admin feature area. We'll update our existing `AuthGuard` to support the `CanLoad` guard. We'll import the `CanLoad` interface and the `Route` the guard provides when called that contains the requested path. - + 我们可以用`CanLoad`守卫来保证只在用户已经登录并尝试访问管理特性区时才加载一次`AdminModule`。我们这就升级`AuthGuard`来支持`CanLoad`守卫。我们先导入`CanLoad`接口,它被调用时守卫会提供一个`Route`参数,其中包含所请求的路径。 We'll add the interface to our service, and then we'll implement the interface. Since our `AuthGuard` already checks the user's logged in state, we can pass that access check to our `canLoad` method. The `Route` in the `canLoad` method provides a **path** which comes from our route configuration. - + 我们还要把此接口加入到服务中,并实现它。由于我们的`AuthGuard`已经能检查用户的登录状态了,所以把`canLoad`方法的权限检查工作直接转给它。 `canLoad`方法中的`Route`参数提供了一个路径,它来自我们的路由配置。 @@ -3681,7 +3677,7 @@ h3#can-load-guard CanLoad守卫: 保护特性模块的加载 :marked Next, we'll import the `AuthGuard` into our `app-routing.module.ts` and add the `AuthGuard` to the `canLoad` array for our `admin` route. Now our `admin` feature area is only loaded when the proper access has been granted. - + 接下来,我们就把`AuthGuard`导入到`app.routing.ts`中,并把`AuthGuard`添加到`admin`路由的`canLoad`数组中。现在`admin`特性区就只有当获得访问授权时才会被加载了。 +makeExcerpt('app/app-routing.module.5.ts (can load guard)', 'can-load-guard') @@ -3720,7 +3716,7 @@ h3#preloading 预加载: 在后台加载特征区域 *路由器*还支持[自定义预加载策略](#custom-preloading),用来精细控制预加载。 - We'll update our *CrisisCenterModule* to be loaded lazily by default and use the `PreloadAllModules` strategy + We'll update our *CrisisCenterModule* to be loaded lazily by default and use the `PreloadAllModules` strategy to load _all_ lazy loaded modules as soon as possible. 我们将更新*CrisisCenterModule*,让它默认惰性加载并使用`PreloadAllModules`策略来尽快加载_所有_惰性加载模块。 @@ -3768,14 +3764,14 @@ h3#preloading 预加载: 在后台加载特征区域 `) :marked - The second argument in the `RouterModule.forRoot` method takes an object for additional configuration options. + The second argument in the `RouterModule.forRoot` method takes an object for additional configuration options. We import the `PreloadAllModules` token from the router package and set the configuration option's `preloadingStrategy` property - with this `PreloadAllModules` token. + with this `PreloadAllModules` token. This tells the built-in *Router* pre-loader to immediately load **all** [unguarded](#preload-canload) feature areas that use `loadChildren`. `RouterModule.forRoot`方法的第二个参数接受一个附加配置选项对象。 我们从路由器包导入`PreloadAllModules`令牌,并将这个配置选项的`preloadingStrategy`属性设置为`PreloadAllModules`令牌。 - 这样,内置的*路由器*立刻预加载**所有**使用`loadChildren`的[未受保护](#preload-canload)的特征区域。 + 这样,内置的*路由器*立刻预加载**所有**使用`loadChildren`的[未受保护](#preload-canload)的特征区域。 +makeExcerpt('app/app-routing.module.6.ts (preload all)', '') @@ -3807,7 +3803,7 @@ h3#preloading 预加载: 在后台加载特征区域 因为想利用这点,我们将添加自定义策略,_只_预加载我们选择的模块。为了启用预加载,我们使用*Route Data*,正如我们学过的,它是储存的路由数据和[解析数据](#resolve-guard)对象。 - We'll add a custom `preload` boolean to our `crisis-center` route data that we'll use with our custom strategy. To see it in action, we'll add + We'll add a custom `preload` boolean to our `crisis-center` route data that we'll use with our custom strategy. To see it in action, we'll add the `route.path` to the `preloadedModules` array in our custom strategy service. We'll also log a message to the console for the preloaded module. @@ -3842,7 +3838,7 @@ h3#preloading 预加载: 在后台加载特征区域 To confirm our *CrisisCenterModule* is being pre-loaded, we'll display our `preloadedModules` in the `Admin` dashboard. We already know how to use an *ngFor* loop, so we'll skip over the details here. Since the `PreloadSelectedModules` is just a service, we can inject it into the `AdminDashboardComponent` and wire it up to our list. - + 要确认*CrisisCenterModule*是否被预加载,我们将在`Admin`管理控制台显示`preloadedModules`。 我们已经知道如何使用*ngFor*循环,所以在这里跳过了一些细节。因为`PreloadSelectedModules`只是一个服务,我们可以将其注入到`AdminDashboardComponent`并连接到列表中: @@ -3886,7 +3882,6 @@ h3#preloading 预加载: 在后台加载特征区域 该附件中的内容不是必须的,感兴趣的人才需要阅读它。 - .l-main-section#link-parameters-array :marked ## Appendix: Link Parameters Array @@ -3894,25 +3889,25 @@ h3#preloading 预加载: 在后台加载特征区域 ## 附录:链接参数数组 We've mentioned the *Link Parameters Array* several times. We've used it several times. - + 我们已经数次提及*链接参数数组*,也用过好几次了。 A link parameters array holds the ingredients for router navigation: - + 链接参数数组保存路由导航时所需的成分: - + * the *path* of the route to the destination component - + * 指向目标组件的那个路由的*路径(path)* - + * required and optional route parameters that go into the route URL - + * 必备路由参数和可选路由参数,它们将进入该路由的URL We can bind the `RouterLink` directive to such an array like this: - + 我们可以把`RouterLink`指令绑定到一个数组,就像这样: - + +makeExcerpt('app/app.component.3.ts', 'h-anchor', '') :marked @@ -3924,9 +3919,9 @@ h3#preloading 预加载: 在后台加载特征区域 :marked We can provide optional route parameters in an object like this: - + 我们可以在对象中提供可选的路由参数,就像这样: - + +makeExcerpt('app/app.component.3.ts', 'cc-query-params', '') :marked @@ -4131,7 +4126,6 @@ code-example(format=".", language="bash"). 要学习关于“提供商”和启动过程的更多知识,参见[依赖注入](dependency-injection.html#bootstrap)一章。 - :marked ### Which Strategy is Best? diff --git a/public/docs/ts/latest/guide/server-communication.jade b/public/docs/ts/latest/guide/server-communication.jade index 5f23812736..ba862b98fa 100644 --- a/public/docs/ts/latest/guide/server-communication.jade +++ b/public/docs/ts/latest/guide/server-communication.jade @@ -7,120 +7,120 @@ block includes :marked [HTTP](https://tools.ietf.org/html/rfc2616) is the primary protocol for browser/server communication. - + [HTTP](https://tools.ietf.org/html/rfc2616)是浏览器和服务器之间通讯的主要协议。 .l-sub-section :marked The [`WebSocket`](https://tools.ietf.org/html/rfc6455) protocol is another important communication technology; it isn't covered in this page. - + [`WebSocket`](https://tools.ietf.org/html/rfc6455)协议是另一种重要的通讯技术,但本章不会涉及它。 :marked Modern browsers support two HTTP-based APIs: [XMLHttpRequest (XHR)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) and [JSONP](https://en.wikipedia.org/wiki/JSONP). A few browsers also support [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). - + 现代浏览器支持两种基于HTTP的API: - [XMLHttpRequest (XHR)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)和 + [XMLHttpRequest (XHR)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)和 [JSONP](https://en.wikipedia.org/wiki/JSONP)。少数浏览器还支持 - [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)。 + [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)。 The !{_Angular_http_library} simplifies application programming with the **XHR** and **JSONP** APIs. This page covers: - + !{_Angular_http_libraryCn}简化了**XHR**和**JSONP** API的编程,这就是本章所要讲的。 - [The Tour of Heroes *HTTP* client demo](#http-client). - + - [英雄指南范例的HTTP客户端](#http-client) - + - [Fetch data with http.get](#fetch-data). - + - [用http.get获取数据](#fetch-data) - +
  • [RxJS library](#rxjs).
  • - +
  • [RxJS库](#rxjs)
  • - +
  • [Enable RxJS operators](#enable-rxjs-operators).
  • - +
  • [启用RxJS操作符](#enable-rxjs-operators)
  • - + - [Process the response object](#extract-data). - + - [处理响应对象](#extract-data) - + - [Always handle errors](#error-handling). - + - [总是处理错误](#error-handling) - + - [Send data to the server](#update). - + - [把数据发送到服务器](#update) - +
  • [Fall back to promises](#promises).
  • - +
  • [使用承诺(Promise)来取代可观察对象(Observable)](#promises)
  • - + - [Cross-Origin Requests: Wikipedia example](#cors). - + - [跨域请求:Wikipedia例子](#cors) - +
    • [Search parameters](#search-parameters).
    • - +
    • [设置查询参数](#search-parameters)
    • - +
    • [More fun with observables](#more-observables).
    • - +
    • [限制搜索词输入频率](#more-observables)
    • - +
    - [Guarding against Cross-Site Request Forgery](#xsrf) - + - [防止跨站请求伪造](#xsrf) - + - [Appendix: Tour of Heroes in-memory server](#in-mem-web-api). - + - [附录:英雄指南的内存Web API服务](#in-mem-web-api) A live example illustrates these topics. - + 我们在在线例子中展示了这些主题。 - + .l-main-section :marked # Demos - + # 演示 This page describes server communication with the help of the following demos: - + 本章通过下面这些演示,描述了服务端通讯的用法。 block demos-list :marked - [The Tour of Heroes *HTTP* client demo](#http-client). - + - [英雄指南HTTP客户端](#http-client) - + - [Fall back to !{_Promise}s](#promises). - + - [回到使用承诺](#promises) - + - [Cross-Origin Requests: Wikipedia example](#cors). - + - [跨站请求:Wikipedia例子](#cors) - + - [More fun with observables](#more-observables). - + - [更多可观察对象的探索](#more-observables) :marked The root `AppComponent` orchestrates these demos: - + 这些演示由根组件`AppComponent`统一演示。 +makeExample('server-communication/ts/app/app.component.ts', null, 'app/app.component.ts') @@ -128,23 +128,23 @@ block demos-list :marked There is nothing remarkable here _except_ for the import of RxJS operators, which is described [later](#rxjs). - + 这里唯一值得注意的是对RxJS操作符的导入,[后面](#rxjs)有详细介绍。 +makeExample('server-communication/ts/app/app.component.ts', 'import-rxjs')(format='.') .l-main-section#http-providers :marked # Providing HTTP services - + # 提供HTTP服务 - + First, configure the application to use server communication facilities. 首先,配置应用来使用服务器对话设施。 - + The !{_Angular_Http} client communicates with the server using a familiar HTTP request/response protocol. The `!{_Http}` client is one of a family of services in the !{_Angular_http_library}. - + 我们通过!{_Angular_Http}客户端,使用熟悉的HTTP请求/回应协议与服务器通讯。`!{_Http}`客户端是!{_Angular_http_libraryCn}所提供的服务大家庭中的一员。 +ifDocsFor('ts') @@ -153,22 +153,23 @@ block demos-list When importing from the `@angular/http` module, SystemJS knows how to load services from the !{_Angular_http_library} because the `systemjs.config.js` file maps to that module name. - + 当我们从`@angular/http`模块中导入服务时,SystemJS知道该如何从!{_Angular_http_libraryCn}中加载它们,这是因为我们已经在`system.config`文件中注册过这个模块名。 + :marked Before you can use the `!{_Http}` client, you need to register it as a service provider with the dependency injection system. - + 要想使用`#{_Http}`客户端,我们得先通过依赖注入系统把它注册成一个服务提供商。 - + .l-sub-section :marked Read about providers in the [Dependency Injection](dependency-injection.html) page. - + 了解关于提供商的更多知识,参见[依赖注入](dependency-injection.html)一章。 :marked Register providers by importing other NgModules to the root NgModule in `app.module.ts`. - + 在`app.module.ts`中通过导入其他模块来注册提供商到根NgModule。 +makeExample('server-communication/ts/app/app.module.1.ts', null, 'app/app.module.ts (v1)')(format='.') @@ -177,45 +178,45 @@ block http-providers :marked Begin by importing the necessary members. The newcomers are the `HttpModule` and the `JsonpModule` from the !{_Angular_http_library}. For more information about imports and related terminology, see the [MDN reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) on the `import` statement. - + 我们从导入所需的符号开始,它们中的大多数我们都熟悉了,只有`HttpModule`和`JsonpModule`是新面孔。 - + To add these modules to the application, pass them to the `imports` array in the root `@NgModule`. - + 只要把它们传给我们这个根模块的`imports`数组,就可以把这些模块加入本应用。 - + .l-sub-section :marked The `HttpModule` is necessary for making HTTP calls. Though the JsonpModule isn't necessary for plain HTTP, there is a JSONP demo later in this page. Loading its module now saves time. - + 我们需要HttpModule来发起HTTP调用。普通的HTTP调用并不需要用到JsonpModule, 不过稍后我们就会演示对JSONP的支持,所以现在就加载它,免得再回来改浪费时间。 - + .l-main-section#http-client :marked - # The Tour of Heroes HTTP client demo - - # 《英雄指南》的HTTP客户端演示 + ## The Tour of Heroes HTTP client demo + + ## 《英雄指南》的HTTP客户端演示 The first demo is a mini-version of the [tutorial](../tutorial)'s "Tour of Heroes" (ToH) application. This version gets some heroes from the server, displays them in a list, lets the user add new heroes, and saves them to the server. The app uses the !{_Angular_Http} client to communicate via `XMLHttpRequest (XHR)`. - + 我们的第一个演示是《英雄指南(TOH)》教程的一个迷你版。 这个版本从服务器获取一些英雄,把它们显示在列表中,还允许我们添加新的英雄并将其保存到服务器。 借助!{_Angular_Http}客户端,我们通过`XMLHttpRequest (XHR)`与服务器通讯。 It works like this: - + 它跑起来是这样的: figure.image-display img(src='/resources/images/devguide/server-communication/http-toh.gif' alt="ToH mini app" width="250") :marked This demo has a single component, the `HeroListComponent`. Here's its template: - + 这个范例是一个单一组件`HeroListComponent`,其模板如下: +makeExample('server-communication/ts/app/toh/hero-list.component.html', null, 'app/toh/hero-list.component.html (template)') :marked @@ -226,49 +227,49 @@ figure.image-display value of the input box in the `(click)` event binding. When the user clicks the button, that value passes to the component's `addHero` method and then the event binding clears it to make it ready for a new hero name. - + 它使用`ngFor`来展现这个英雄列表。 列表的下方是一个输入框和一个*Add Hero*按钮,在那里,我们可以输入新英雄的名字,并把它们加到数据库中。 在`(click)`事件绑定中,我们使用[模板引用变量](template-syntax.html#ref-vars)`newHeroName`来访问这个输入框的值。 当用户点击此按钮时,我们把这个值传给组件的`addHero`方法,然后清除它,以备输入新英雄的名字。 - + Below the button is an area for an error message. - + 按钮的下方是一个错误信息区。 a#oninit a#HeroListComponent :marked - ## The *HeroListComponent* class + ### The *HeroListComponent* class + + ### *HeroListComponent*类 - ## *HeroListComponent*类 - Here's the component class: - + 下面是这个组件类: -+makeExample('server-communication/ts/app/toh/hero-list.component.ts','component', 'app/toh/hero-list.component.ts (class)') ++makeExample('server-communication/ts/app/toh/hero-list.component.ts','component', 'app/toh/hero-list.component.ts (class)') :marked Angular [injects](dependency-injection.html) a `HeroService` into the constructor and the component calls that service to fetch and save data. - + Angular会把一个`HeroService`[注入](dependency-injection.html)到组件的构造函数中,该组件将调用此服务来获取和保存数据。 The component **does not talk directly to the !{_Angular_Http} client**. The component doesn't know or care how it gets the data. It delegates to the `HeroService`. - + 这个组件**不会直接和!{_Angular_Http}客户端打交道**! 它既不知道也不关心我们如何获取数据,这些都被委托给了`HeroService`去做。 - + This is a golden rule: **always delegate data access to a supporting service class**. - + 这是一条“黄金法则”:**总是把数据访问工作委托给一个支持服务类**。 Although _at runtime_ the component requests heroes immediately after creation, you **don't** call the service's `get` method in the component's constructor. Instead, call it inside the `ngOnInit` [lifecycle hook](lifecycle-hooks.html) and rely on Angular to call `ngOnInit` when it instantiates this component. - + 虽然_在运行期间_,组件会在创建之后立刻请求这些英雄数据,但我们**不**在组件的构造函数中调用此服务的`get`方法。 而是在`ngOnInit`[生命周期钩子](lifecycle-hooks.html)中调用它,Angular会在初始化该组件时调用`ngOnInit`方法。 .l-sub-section @@ -276,70 +277,71 @@ a#HeroListComponent This is a *best practice*. Components are easier to test and debug when their constructors are simple, and all real work (especially calling a remote server) is handled in a separate method. - + 这是*最佳实践*。 当组件的构造函数足够简单,并且所有真实的工作(尤其是调用远端服务器)都在一个独立的方法中处理时,组件会更加容易测试和调试。 block getheroes-and-addhero :marked The service's `getHeroes()` and `addHero()` methods return an `Observable` of hero data that the !{_Angular_Http} client fetched from the server. - + 服务的`getHeroes()`和`addHero()`方法返回一个英雄数据的可观察对象(`Observable`),这些数据是由!{_Angular_Http}从服务器上获取的。 - + Think of an `Observable` as a stream of events published by some source. To listen for events in this stream, ***subscribe*** to the `Observable`. These subscriptions specify the actions to take when the web request produces a success event (with the hero data in the event payload) or a fail event (with the error in the payload). - + 我们可以把可观察对象`Observable`看做一个由某些“源”发布的事件流。 通过***订阅***到可观察对象`Observable`,我们监听这个流中的事件。 在这些订阅中,我们指定了当Web请求生成了一个成功事件(有效载荷是英雄数据)或失败事件(有效载荷是错误对象)时该如何采取行动。 :marked With a basic understanding of the component, you're ready to look inside the `HeroService`. - + 关于组件的浅显讲解已经结束了,我们可以到`HeroService`的内部实现中看看。 a#HeroService .l-main-section#fetch-data :marked ## Fetch data with http.get - + ## 通过http.get获取数据 In many of the previous samples the app faked the interaction with the server by returning mock heroes in a service like this one: - + 在前面的很多例子中,我们通过在服务中返回一个模拟的英雄列表来伪造了与服务器的交互过程。就像这样: - + +makeExample('toh-4/ts/app/hero.service.ts', 'just-get-heroes')(format=".") :marked You can revise that `HeroService` to get the heroes from the server using the !{_Angular_Http} client service: - + 在本章中,我们会修改`HeroService`,改用“!{_Angular_Http}客户端”服务来从服务器上获取英雄列表: +makeExample('server-communication/ts/app/toh/hero.service.ts', 'v1', 'app/toh/hero.service.ts (revised)') :marked Notice that the !{_Angular_Http} client service is [injected](dependency-injection.html) into the `HeroService` constructor. - + 注意,这个“!{_Angular_Http}客户端”服务[被注入](dependency-injection.html)到了`HeroService`的构造函数中。 +makeExample('server-communication/ts/app/toh/hero.service.ts', 'ctor') :marked Look closely at how to call `!{_priv}http.get`: - + 仔细看看我们是如何调用`!{_priv}http.get`的 - + +makeExample('server-communication/ts/app/toh/hero.service.ts', 'http-get', 'app/toh/hero.service.ts (getHeroes)')(format=".") :marked You pass the resource URL to `get` and it calls the server which returns heroes. - + 我们把资源的URL传进`get`函数,它调用了服务器,而服务器应该返回英雄列表。 + .l-sub-section :marked The server returns heroes once you've set up the [in-memory web api](#in-mem-web-api) described in the appendix below. Alternatively, you can temporarily target a JSON file by changing the endpoint URL: - + 一旦我们按附录中所描述的那样准备好了[内存Web API](in-mem-web-api),它*将*返回英雄列表。 但目前,我们只能(临时性的)使用一个JSON文件来代替这个“内存Web API”。只要修改下服务器的URL就行了: +makeExample('server-communication/ts/app/toh/hero.service.ts', 'endpoint-json')(format=".") @@ -361,30 +363,29 @@ a#HeroService In fact, the `http.get` method returns an **Observable** of HTTP Responses (`Observable`) from the RxJS library and `map` is one of the RxJS *operators*. - + 事实上,`http.get`方法返回了一个HTTP Response类型的**可观察对象**(`Observable`),这个对象来自RxJS库,而`map`是RxJS的*操作符*之一。 .l-main-section :marked - # RxJS library + ## RxJS library - # RxJS库 + ## RxJS库 [RxJS](https://github.com/ReactiveX/RxJS) ("Reactive Extensions") is a 3rd party library, endorsed by Angular, that implements the [*asynchronous observable*](https://www.youtube.com/watch?v=UHI0AzD_WfY "Rob Wormald on observables") pattern. - + [RxJS](https://github.com/ReactiveX/RxJS)("Reactive Extensions"的缩写)是一个被Angular认可的第三方库,它实现了 [*异步可观察对象(asynchronous observable)*](https://www.youtube.com/watch?v=UHI0AzD_WfY "Rob Wormald on observables")模式。 All of the Developer Guide samples have installed the RxJS npm package and loaded via `system.js` because observables are used widely in Angular applications. - + 本开发指南中的所有例子都安装了RxJS的npm包,而且都被`system.js`加载过了。这是因为可观察对象在Angular应用中使用非常广泛。 - + The app needs it when working with the HTTP client. Additionally, you must take a critical extra step to make RxJS observables usable. - - + HTTP客户端更需要它。经过一个关键步骤,我们才能让RxJS可观察对象可用。 ### Enable RxJS operators @@ -394,7 +395,7 @@ a#HeroService The RxJS library is large. Size matters when building a production application and deploying it to mobile devices. You should include only necessary features. - + RxJS库实在是太大了。 当构建一个产品级应用,并且把它发布到移动设备上的时候,大小就会成为一个问题。 我们应该只包含那些我们确实需要的特性。 @@ -402,51 +403,53 @@ a#HeroService Accordingly, Angular exposes a stripped down version of `Observable` in the `rxjs/Observable` module that lacks most of the operators such as the `map` method you called above in `getHeroes`. - + 因此,Angular在`rxjs/Observable`模块中导出了一个精简版的`Observable`类,这个版本缺少很多操作符, 比如我们在上面的`getHeroes`方法中用过的`map`函数。 It's up to you to add the operators you need. - + 这让我们可以自由决定添加哪些操作符。 - + You could add _every_ RxJS operator with a single import statement. While that is the easiest thing to do, you'd pay a penalty in extended launch time and application size because the full library is so big. - + 我们可以通过一条import语句把*每个*RxJS操作符都添加进来。 虽然这是最简单的方式,但我们也得付出代价,主要是在启动时间和应用大小上,因为完整的库实在太大了。 而我们其实只需要用到少量操作符。 - + Since this app only uses a few operators, it's better to import each `Observable` operator and static class method, one-by-one, for a custom *Observable* implementation tuned precisely to the app's requirements. Put the `import` statements in one `app/rxjs-operators.ts` file. - + 因为本应用只使用了少许操作符,所以将一个一个的导入`Observable`的操作符和静态类方法比较合适, 直到我们得到了一个精确符合我们需求的自定义*Observable*实现。 我们将把这些`import`语句放进一个`app/rxjs-operators.ts`文件里。 +makeExample('server-communication/ts/app/rxjs-operators.ts', null, 'app/rxjs-operators.ts')(format=".") :marked If you forget an operator, the TypeScript compiler warns that it's missing and you'll update this file. - + 如果忘了导入某个操作符,TypeScript编译器就会警告说找不到它,那时候我们再来更新此文件。 .l-sub-section :marked The app doesn't need _all_ of these particular operators in the `HeroService` — just `map`, `catch` and `throw`. The other operators are for later, in the *Wiki* example [below](#more-observables). - + 在`HeroService`中,我们并不需要在这里导入的_全部_操作符 —— 我们只用到了`map`、`catch`和`throw`。 我们稍后的[*Wiki*例子](#more-observables)中,还会用到其它操作符。 :marked Finally, import `rxjs-operator` into `app.component.ts`: - + 最后,我们把`rxjs-operator`_本身_导入`app.component.ts`文件中: +makeExample('server-communication/ts/app/app.component.ts', 'import-rxjs', 'app/app.component.ts (import rxjs)')(format=".") + :marked Now continue to the next section to return to the `HeroService`. - + 现在,继续到下一节,返回到`HeroService`。 + .l-main-section a#extract-data :marked @@ -455,13 +458,13 @@ a#extract-data ## 处理Response响应对象 Remember that the `getHeroes()` method used an `!{_priv}extractData` helper method to map the `!{_priv}http.get` response object to heroes: - + 记住,`getHeroes()`借助一个`!{_priv}extractData`辅助方法来把`!{_priv}http.get`的响应对象映射成了英雄列表: +makeExample('server-communication/ts/app/toh/hero.service.ts', 'extract-data', 'app/toh/hero.service.ts (excerpt)')(format=".") :marked The `response` object doesn't hold the data in a form the app can use directly. You must parse the response data into a JSON object. - + 这个`response`对象并没有以一种我们能直接使用的格式来保存数据。 要让它在应用程序中可用,我们就必须把这个响应数据解析成一个JSON对象。 @@ -472,7 +475,7 @@ block parse-json :marked The response data are in JSON string form. The app must parse that string into JavaScript objects by calling `response.json()`. - + 响应数据是JSON字符串格式的。 我们必须把这个字符串解析成JavaScript对象 —— 只要调一下`response.json()`就可以了。 @@ -482,7 +485,7 @@ block parse-json The Angular HTTP client follows the Fetch specification for the [response object](https://fetch.spec.whatwg.org/#response-class) returned by the `Fetch` function. That spec defines a `json()` method that parses the response body into a JavaScript object. - + 这不是Angular自己的设计。 Angular HTTP客户端遵循ES2015规范来处理`Fetch`函数返回的[响应对象](https://fetch.spec.whatwg.org/#response-class)。 此规范中定义了一个`json()`函数,来把响应体解析成JavaScript对象。 @@ -494,16 +497,17 @@ block parse-json property. You have to unwrap it to get the heroes. This is conventional web API behavior, driven by [security concerns](https://www.owasp.org/index.php/OWASP_AJAX_Security_Guidelines#Always_return_JSON_with_an_Object_on_the_outside). - + 我们不应该期待解码后的JSON直接就是一个英雄数组。 调用的这个服务器总会把JSON结果包装进一个带`data`属性的对象中。 我们必须解开它才能得到英雄数组。这是一个约定俗成的Web API行为规范,它是出于 [安全方面的考虑](https://www.owasp.org/index.php/OWASP_AJAX_Security_Guidelines#Always_return_JSON_with_an_Object_on_the_outside)。 + .alert.is-important :marked Make no assumptions about the server API. Not all servers return an object with a `data` property. - + 不要对服务端API做任何假设。 并非所有服务器都会返回一个带`data`属性的对象。 :marked @@ -534,7 +538,7 @@ block parse-json [*cold*](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md#cold-vs-hot-observables), which means that the request won't go out until something *subscribes* to the observable. That *something* is the [HeroListComponent](#subscribe). - + `#{_priv}http.get`**仍然没有发送请求!**这是因为可观察对象是 [*冷淡的*](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md#cold-vs-hot-observables), 也就是说,只有当某人*订阅*了这个可观察对象时,这个请求才会被发出。 @@ -550,20 +554,23 @@ a#error-handling and do something with them. One way to handle errors is to pass an error message back to the component for presentation to the user, but only if it says something that the user can understand and act upon. - + 一旦开始与I/O打交道,我们就必须准备好接受墨菲定律:如果一件倒霉事*可能*发生,它就*迟早会*发生。 我们可以在`HeroService`中捕获错误,并对它们做些处理。 只有在用户可以理解并采取相应行动的时候,我们才把错误信息传回到组件,让组件展示给最终用户。 This simple app conveys that idea, albeit imperfectly, in the way it handles a `getHeroes` error. - + 在这个简单的应用中,我们在服务和组件中都只提供了最原始的错误处理方式。 + ++makeExample('server-communication/ts/app/toh/hero.service.ts', 'error-handling', 'app/toh/hero.service.ts (excerpt)')(format=".") + block error-handling :marked The `catch` operator passes the error object from `http` to the `handleError` method. The `handleError` method transforms the error into a developer-friendly message, logs it to the console, and returns the message in a new, failed observable via `Observable.throw`. - + `catch`操作符将错误对象传递给`http`的`handleError`方法。 服务处理器(`handleError`)把响应对象记录到控制台中, 把错误转换成对用户友好的消息,并且通过`Observable.throw`来把这个消息放进一个新的、用于表示“失败”的可观察对象。 @@ -580,19 +587,18 @@ block hlc-error-handling Back in the `HeroListComponent`, in `!{_priv}heroService.getHeroes()`, the `subscribe` function has a second function parameter to handle the error message. It sets an `errorMessage` variable that's bound conditionally in the `HeroListComponent` template. - + 回到`HeroListComponent`,这里我们调用了`#{_priv}heroService.getHeroes()`。我们提供了`subscribe`函数的第二个参数来处理错误信息。 它设置了一个`errorMessage`变量,被有条件的绑定到了`HeroListComponent`模板中。 +makeExample('server-communication/ts/app/toh/hero-list.component.ts', 'getHeroes', 'app/toh/hero-list.component.ts (getHeroes)')(format=".") - + .l-sub-section :marked Want to see it fail? In the `HeroService`, reset the api endpoint to a bad value. Afterward, remember to restore it. - + 想看到它失败时的情况吗?在`HeroService`中把API的端点设置为一个无效值就行了。但别忘了恢复它。 - .l-main-section @@ -600,48 +606,48 @@ block hlc-error-handling ## Send data to the server ## 往服务器发送数据 - + So far you've seen how to retrieve data from a remote location using an HTTP service. Now you'll add the ability to create new heroes and save them in the backend. - + 前面我们已经看到如何用一个HTTP服务从远端获取数据了。 但我们还能再给力一点,让它可以创建新的英雄,并把它们保存到后端。 You'll write a method for the `HeroListComponent` to call, an `addHero()` method, that takes just the name of a new hero and returns an `Observable` of `Hero`. It begins like this: - + 我们将为`HeroListComponent`创建一个简单的`addHero()`方法,它将接受新英雄的名字: +makeExample('server-communication/ts/app/toh/hero.service.ts', 'addhero-sig')(format=".") :marked To implement it, you must know the server's API for creating heroes. - + 要实现它,我们得知道关于服务端API如何创建英雄的一些细节。 - + [This sample's data server](#server) follows typical REST guidelines. It expects a [`POST`](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5) request at the same endpoint as `GET` heroes. It expects the new hero data to arrive in the body of the request, structured like a `Hero` entity but without the `id` property. The body of the request should look like this: - + 我们的[数据服务器](#server)遵循典型的REST指导原则。 它期待在和`GET`英雄列表的同一个端点上存在一个[`POST`](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5)请求。 它期待从请求体(body)中获得新英雄的数据,数据的结构和`Hero`对象相同,但是不带`id`属性。 请求体应该看起来像这样: - + code-example(format="." language="javascript"). { "name": "Windstorm" } :marked The server generates the `id` and returns the entire `JSON` representation of the new hero including its generated id. The hero arrives tucked inside a response object with its own `data` property. - + 服务器将生成`id`,并且返回新英雄的完整`JSON`形式,包括这个生成的id。该英雄的数据被塞进一个响应对象的`data`属性中。 - + Now that you know how the API works, implement `addHero()`as follows: - + 现在,知道了这个API如何工作,我们就可以像这样实现`addHero()`了: +ifDocsFor('ts') @@ -654,7 +660,7 @@ code-example(format="." language="javascript"). ### 请求头(Headers) In the `headers` object, the `Content-Type` specifies that the body represents JSON. - + 我们通过`Content-Type`头告诉服务器,body是JSON格式的。 +ifDocsFor('ts') @@ -662,14 +668,13 @@ code-example(format="." language="javascript"). Next, the `headers` object is used to configure the `options` object. The `options` object is a new instance of `RequestOptions`, a class that allows you to specify certain settings when instantiating a request. In this way, [headers](../api/http/index/Headers-class.html) is one of the [RequestOptions](../api/http/index/RequestOptions-class.html). - + 接下来,使用`headers`对象来配置`options`对象。 `options`对象是`RequestOptions`的新实例,该类允许你在实例化请求时指定某些设置。这样, [Headers](../api/http/index/Headers-class.html)是[RequestOptions](../api/http/index/RequestOptions-class.html)中的一员。 - - + In the `return` statement, `options` is the *third* argument of the `post` method, as shown above. - + 在`return`声明中,`options`是传给`post`方法的*第三个*参数,就像前面见过的那样。 :marked @@ -679,14 +684,14 @@ code-example(format="." language="javascript"). As with `getHeroes()`, use the `!{_priv}extractData()` helper to [extract the data](#extract-data) from the response. - + 像`getHeroes()`中一样,我们可以使用`!{_priv}extractData()`辅助函数从响应中[提取出数据](#extract-data)。 block hero-list-comp-add-hero :marked Back in the `HeroListComponent`, *its* `addHero()` method subscribes to the observable returned by the *service's* `addHero()` method. When the data arrive it pushes the new hero object into its `heroes` array for presentation to the user. - + 回到`HeroListComponent`,我们看到*该组件的*`addHero()`方法中订阅了这个由*服务中*的`addHero()`方法返回的可观察对象。 当有数据到来时,它就会把这个新的英雄对象追加(push)到`heroes`数组中,以展现给用户。 +makeExample('server-communication/ts/app/toh/hero-list.component.ts', 'addHero', 'app/toh/hero-list.component.ts (addHero)')(format=".") @@ -700,7 +705,7 @@ block hero-list-comp-add-hero [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). It's easy to do, and in simple cases, a promise-based version looks much like the observable-based version. - + 虽然Angular的`http`客户端API返回的是`Observable`类型的对象,但我们也可以把它转成 [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)。 这很容易,并且在简单的场景中,一个基于承诺(Promise)的版本看起来很像基于可观察对象(Observable)的版本。 @@ -708,11 +713,11 @@ block hero-list-comp-add-hero :marked While promises may be more familiar, observables have many advantages. - 可能“承诺”看起来更熟悉一些,但“可观察对象”有很多优越之处。 + 可能“承诺”看起来更熟悉一些,但“可观察对象”有很多优越之处。 :marked Here is a comparison of the `HeroService` using promises versus observables, highlighting just the parts that are different. - + 下面是使用承诺重写`HeroService`,要特别注意那些不同的部分。 +makeTabs( 'server-communication/ts/app/toh/hero.service.promise.ts,server-communication/ts/app/toh/hero.service.ts', @@ -721,25 +726,24 @@ block hero-list-comp-add-hero :marked You can follow the promise `then(this.extractData).catch(this.handleError)` pattern as in this example. - + 在本例中,你可以遵循承诺的`then(this.extractData).catch(this.handleError)`模式。 - Alternatively, you can call `toPromise(success, fail)`. The observable's `map` callback moves to the first *success* parameter - and its `catch` callback to the second *fail* parameter in this pattern: `.toPromise(this.extractData, this.handleError)`. - + Alternatively, you can call `toPromise(success, fail)`. The observable's `map` callback moves to the first *success* parameter and its `catch` callback to the second *fail* parameter in this pattern: `.toPromise(this.extractData, this.handleError)`. + 另外,你也可以调用`toPromise(success, fail)`。可观察对象的`map`第一个参数为*成功*时的回调函数, 它的第二个参数用`.toPromise(this.extractData, this.handleError)`来拦截失败。 The `errorHandler` forwards an error message as a failed promise instead of a failed `observable`. - + 我们的`errorHandler`也改用了一个失败的承诺,而不再是失败的可观察对象。 The diagnostic *log to console* is just one more `then` in the promise chain. - + 把诊断信息*记录到控制台*也只是在承诺的处理链中多了一个`then`而已。 You have to adjust the calling component to expect a `Promise` instead of an `observable`: - + 我们还得对调用方组件进行调整,让它期待一个`Promise`而非`Observable`: +makeTabs( @@ -749,29 +753,29 @@ block hero-list-comp-add-hero :marked The only obvious difference is that you call `then` on the returned promise instead of `subscribe`. Both methods take the same functional arguments. - + 唯一一个比较明显的不同点是我们调用这个返回的承诺的`then`方法,而不再是`subscribe`。 我们给了这两个方法完全相同的调用参数。 .l-sub-section :marked The less obvious but critical difference is that these two methods return very different results. - + 细微却又关键的不同点是,这两个方法返回了非常不同的结果! The promise-based `then` returns another promise. You can keep chaining more `then` and `catch` calls, getting a new promise each time. - + 基于承诺的`then`返回了另一个承诺。我们可以链式调用多个`then`和`catch`方法,每次都返回一个新的承诺。 The `subscribe` method returns a `Subscription`. A `Subscription` is not another `Observable`. It's the end of the line for observables. You can't call `map` on it or call `subscribe` again. The `Subscription` object has a different purpose, signified by its primary method, `unsubscribe`. - + 但`subscribe`方法返回一个`Subscription`对象。但`Subscription`不是另一个`Observable`。 它是可观察对象的末端。我们不能在它上面调用`map`函数或再次调用`subscribe`函数。 `Subscription`对象的设计目的是不同的,这从它的主方法`unsubscribe`就能看出来。 To understand the implications and consequences of subscriptions, watch [Ben Lesh's talk on observables](https://www.youtube.com/watch?v=3LKMwkuK0ZE) or his video course on [egghead.io](https://egghead.io/lessons/rxjs-rxjs-observables-vs-promises). - + 要理解订阅Subscription的实现和效果,请看[Ben Lesh关于可观察对象的演讲](https://www.youtube.com/watch?v=3LKMwkuK0ZE) 或者他在[egghead.io](https://egghead.io/lessons/rxjs-rxjs-observables-vs-promises)的课程。 @@ -780,7 +784,7 @@ h2#cors 跨域请求:Wikipedia范例 :marked You just learned how to make `XMLHttpRequests` using the !{_Angular_Http} service. This is the most common approach for server communication, but it doesn't work in all scenarios. - + 我们刚刚学习了用!{_Angular_Http}服务发起`XMLHttpRequests`。 这是与服务器通讯时最常用的方法。 但它不适合所有场景。 @@ -788,7 +792,7 @@ h2#cors 跨域请求:Wikipedia范例 For security reasons, web browsers block `XHR` calls to a remote server whose origin is different from the origin of the web page. The *origin* is the combination of URI scheme, hostname, and port number. This is called the [same-origin policy](https://en.wikipedia.org/wiki/Same-origin_policy). - + 出于安全的考虑,网络浏览器会阻止调用与当前页面不“同源”的远端服务器的`XHR`。 所谓*源*就是URI的协议(scheme)、主机名(host)和端口号(port)这几部分的组合。 这被称为[同源策略](https://en.wikipedia.org/wiki/Same-origin_policy)。 @@ -798,29 +802,29 @@ h2#cors 跨域请求:Wikipedia范例 Modern browsers do allow `XHR` requests to servers from a different origin if the server supports the [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) protocol. If the server requires user credentials, you'll enable them in the [request headers](#headers). - + 在现代浏览器中,如果服务器支持[CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)协议,那么也可以向不同源的服务器发起`XHR`请求。 如果服务器要请求用户凭证,我们就在[请求头](#headers)中启用它们。 :marked Some servers do not support CORS but do support an older, read-only alternative called [JSONP](https://en.wikipedia.org/wiki/JSONP). Wikipedia is one such server. - + 有些服务器不支持CORS,但支持一种老的、只读的(译注:即仅支持GET)备选协议,这就是[JSONP](https://en.wikipedia.org/wiki/JSONP)。 Wikipedia就是一个这样的服务器。 .l-sub-section :marked This [Stack Overflow answer](http://stackoverflow.com/questions/2067472/what-is-jsonp-all-about/2067584#2067584) covers many details of JSONP. - + 这个[StackOverflow上的答案](http://stackoverflow.com/questions/2067472/what-is-jsonp-all-about/2067584#2067584)覆盖了关于JSONP的很多细节。 :marked ### Search wikipedia ### 搜索Wikipedia - + Here is a simple search that shows suggestions from Wikipedia as the user types in a text box: - + 我们来构建一个简单的搜索程序,当我们在文本框中输入时,它会从Wikipedia中获取并显示建议的词汇列表: figure.image-display @@ -831,13 +835,13 @@ block wikipedia-jsonp+ Wikipedia offers a modern `CORS` API and a legacy `JSONP` search API. This example uses the latter. The Angular `Jsonp` service both extends the `!{_Http}` service for JSONP and restricts you to `GET` requests. All other HTTP methods throw an error because JSONP is a read-only facility. - + Wikipedia提供了一个现代的`CORS` API和一个传统的`JSONP`搜索API。在这个例子中,我们使用后者。 Angular的`Jsonp`服务不但通过JSONP扩展了`#{_Http}`服务,而且限制我们只能用`GET`请求。 尝试调用所有其它HTTP方法都将抛出一个错误,因为JSONP是只读的。 As always, wrap the interaction with an Angular data access client service inside a dedicated service, here called `WikipediaService`. - + 像往常一样,我们把和Angular数据访问服务进行交互的代码全都封装在一个专门的服务中。我们称之为`WikipediaService`。 +makeExample('server-communication/ts/app/wiki/wikipedia.service.ts',null,'app/wiki/wikipedia.service.ts') @@ -848,19 +852,19 @@ block wikipedia-jsonp+ 这个构造函数期望Angular给它注入一个`jsonp`服务。 前面我们已经把`JsonpModule`导入到了根模块中,所以这个服务已经可以使用了。 - + :marked ### Search parameters ### 搜索参数 - + The [Wikipedia "opensearch" API](https://www.mediawiki.org/wiki/API:Opensearch) expects four parameters (key/value pairs) to arrive in the request URL's query string. The keys are `search`, `action`, `format`, and `callback`. The value of the `search` key is the user-supplied search term to find in Wikipedia. The other three are the fixed values "opensearch", "json", and "JSONP_CALLBACK" respectively. - + [Wikipedia 的 'opensearch' API](https://www.mediawiki.org/wiki/API:Opensearch)期待在所请求的URL中带四个查询参数(键/值对格式)。 这些键(key)分别是`search`、`action`、`format`和`callback`。 `search`的值是用户提供的用于在Wikipedia中查找的关键字。 @@ -870,28 +874,28 @@ block wikipedia-jsonp+ The `JSONP` technique requires that you pass a callback function name to the server in the query string: `callback=JSONP_CALLBACK`. The server uses that name to build a JavaScript wrapper function in its response, which Angular ultimately calls to extract the data. All of this happens under the hood. - + `JSONP`技术需要我们通过查询参数传给服务器一个回调函数的名字:`callback=JSONP_CALLBACK`。 服务器使用这个名字在它的响应体中构建一个JavaScript包装函数,Angular最终会调用这个包装函数来提取出数据。 这些都是Angular在背后默默完成的,你不会感受到它。 :marked If you're looking for articles with the word "Angular", you could construct the query string by hand and call `jsonp` like this: - + 如果我们要找那些含有关键字“Angular”的文档,我们可以先手工构造出查询字符串,并像这样调用`jsonp`: +makeExample('server-communication/ts/app/wiki/wikipedia.service.1.ts','query-string')(format='.') :marked In more parameterized examples you could build the query string with the Angular `URLSearchParams` helper: - + 在更加参数化的例子中,我们会首选Angular的`URLSearchParams`辅助类来构建查询字符串,就像这样: +makeExample('server-communication/ts/app/wiki/wikipedia.service.ts','search-parameters','app/wiki/wikipedia.service.ts (search parameters)')(format=".") :marked This time you call `jsonp` with *two* arguments: the `wikiUrl` and an options object whose `search` property is the `params` object. - + 这次我们使用了*两个*参数来调用`jsonp`:`wikiUrl`和一个配置对象,配置对象的`search`属性是刚构建的这个`params`对象。 +makeExample('server-communication/ts/app/wiki/wikipedia.service.ts','call-jsonp','app/wiki/wikipedia.service.ts (call jsonp)')(format=".") :marked `Jsonp` flattens the `params` object into the same query string you saw earlier, putting the request on the wire. - + `Jsonp`把`params`对象平面化为一个查询字符串,而这个查询字符串和以前我们直接放在请求中的那个是一样的。 @@ -902,19 +906,19 @@ block wikipedia-jsonp+ Now that you have a service that can query the Wikipedia API turn to the component (template and class) that takes user input and displays search results. - + 现在,我们有了一个可用于查询Wikpedia API的服务, 我们重新回到组件中,接收用户输入,并显示搜索结果。 - + +makeExample('server-communication/ts/app/wiki/wiki.component.html', null, 'app/wiki/wiki.component.html') +makeExample('server-communication/ts/app/wiki/wiki.component.ts', null, 'app/wiki/wiki.component.ts') :marked The template presents an `` element *search box* to gather search terms from the user, and calls a `search(term)` method after each `keyup` event. - + 该组件有一个``元素,它是用来从用户获取搜索关键词的*搜索框*。 在每次`keyup`事件被触发时,它调用`search(term)`方法。 - + +makeExample('server-communication/ts/app/wiki/wiki.component.html', 'keyup', 'wiki/wiki.component.html')(format='.') :marked The component's `search(term)` method delegates to the `WikipediaService`, which returns an @@ -923,7 +927,7 @@ block wikipedia-jsonp+ the app forwards the observable result to the template (via `items`) where the `async` pipe in the `ngFor` handles the subscription. Read more about [async pipes](pipes.html#async-pipe) in the [Pipes](pipes.html) page. - + `search(term)`方法委托我们的`WikipediaService`服务来完成实际操作。该服务返回的是一个字符串数组的可观察对象(`Observable`)。 该组件的内部订阅了这个可观察对象,就像我们曾在`HeroListComponent`中所做的那样, 我们把这个可观察对象作为结果传给模板(通过`items`属性),模板中`ngFor`上的[async(异步)管道](pipes.html#async-pipe)会对这个订阅进行处理。 @@ -932,10 +936,11 @@ block wikipedia-jsonp+ The [async pipe](pipes.html#async-pipe) is a good choice in read-only components where the component has no need to interact with the data. 我们通常在只读组件中使用[async管道](pipes.html#async-pipe),这种组件不需要与数据进行互动。 - + `HeroListComponent` can't use the pipe because `addHero()` pushes newly created heroes into the list. - + 但我们不能在`HeroListComponent`中使用这个管道,这是因为“添加新英雄”特性会把一个新创建的英雄追加到英雄列表中。 + :marked ## A wasteful app @@ -943,7 +948,7 @@ block wikipedia-jsonp+ The wikipedia search makes too many calls to the server. It is inefficient, and potentially expensive on mobile devices with limited data plans. - + 我们这个Wikipedia搜索程序触发了过多的服务器调用(每次按键发一次)。 这样效率很低,而且在流量受限的移动设备上会显得过于昂贵。 @@ -954,7 +959,7 @@ block wikipedia-jsonp+ Presently, the code calls the server after every key stroke. It should only make requests when the user *stops typing* . Here's how it will work after refactoring: - + 我们目前会在每次按键之后调用服务器。 但合理的方式是只在用户*停止输入*之后才发起请求。 这是它*应该*而且*即将使用*的工作方式,我们马上就重构它。 @@ -967,13 +972,13 @@ block wikipedia-jsonp+ Suppose a user enters the word *angular* in the search box and pauses for a while. The application issues a search request for *angular*. - + 假设用户在输入框中输入了单词*angular*,然后稍等片刻。 应用程序就会发出一个对*Angular*的搜索请求。 Then the user backspaces over the last three letters, *lar*, and immediately re-types *lar* before pausing once more. The search term is still _angular_. The app shouldn't make another request. - + 然后,用户用退格键删除了最后三个字符*lar*,并且毫不停顿的重新输入了*lar*。 搜索关键词仍然是“angular”。这时应用程序不应该发起另一个请求。 @@ -983,7 +988,7 @@ block wikipedia-jsonp+ The user enters *angular*, pauses, clears the search box, and enters *http*. The application issues two search requests, one for *angular* and one for *http*. - + 用户输入了*angular*,暂停,清除搜索框,然后输入*http*。 应用程序发起了两个搜索请求,一个搜*angular*,一个搜*http*。 @@ -991,7 +996,7 @@ block wikipedia-jsonp+ A load balancer could dispatch the requests to two different servers with different response times. The results from the first *angular* request might arrive after the later *http* results. The user will be confused if the *angular* results display to the *http* query. - + 哪一个响应会先回来?我们是没法保证的。 负载均衡器可能把这个请求分发给了响应时间不同的两台服务器。 搜*angular*的结果可能晚于稍后搜*http*的结果。 @@ -999,22 +1004,22 @@ block wikipedia-jsonp+ When there are multiple requests in-flight, the app should present the responses in the original request order. That won't happen if *angular* results arrive last. - + 即使有多个尚未返回的请求,应用程序也应该按照原始请求的顺序展示对它们的响应。如果能让*angular*的结果始终在后面返回,就不会发生这样的混乱了。 ## More fun with observables ## Observable的更多乐趣 - - You can address these problems and improve the app with the help of some nifty observable operators. - + + You can address these problems and improve the app with the help of some nifty observable operators. + 借助一些漂亮的可观察对象操作符,我们可以解决这些问题,并提升我们的应用程序。 You could make changes to the `WikipediaService`, but for a better user experience, create a copy of the `WikiComponent` instead and make it smarter. Here's the `WikiSmartComponent` which uses the same template. - + 我们本可以把这些改动合并进`WikipediaService`中,但是为了更好用户体验, 转而拷贝`WikiComponent`,把它变得更智能。 下面是`WikiSmartComponent`,它使用同样的模板: @@ -1022,24 +1027,24 @@ block wikipedia-jsonp+ +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', null, 'app/wiki/wiki-smart.component.ts') :marked ### Create a stream of search terms - + ### 创建一个由搜索关键字组成的“流(Stream)” The template still binds to the search box `keyup` event and passes the complete search box value into the component's `search` method after every user keystroke. - + 模板仍然绑定搜索框的`keyup`事件,并在每次用户按键时,将搜索框的值传递到组件的`search`方法。 +makeExample('server-communication/ts/app/wiki/wiki.component.html', 'keyup', 'app/wiki/wiki.component.html (input)')(format='.') :marked The `WikiSmartComponent` turns the search box values into an observable _stream of search terms_ with the help of a `Subject` which you import from the RxJS observable library: - + 利用从RxJS库导入的`Subject`,`WikiSmartComponent`将搜索框的值变为一个*搜索关键词流*可观察对象: +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'import-subject', 'app/wiki/wiki-smart.component.ts') :marked The component creates a `searchTermStream` as a `Subject` of type `string`. The `search` method adds each new search box value to that stream via the subject's `next` method. - + 组件创建`searchTermStream`为`string`类型的`Subject`。 `search`方法通过`subject`的`next`方法,将每个新搜索框的值添加到数据流中。 @@ -1051,21 +1056,21 @@ block wikipedia-jsonp+ ### 监听搜索关键字 Earlier, you passed each search term directly to the service and bound the template to the service results. - + 以前,我们每次都把搜索关键字直接传给服务,并且把模板绑定到服务返回的结果。 - + Now you listen to the *stream of search terms*, manipulating the stream before it reaches the `WikipediaService`. - + 而现在我们在监听*关键字组成的流*,并在把它传给`WikipediaService`之前操作这个流。 - - +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'observable-operators', + + +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'observable-operators', 'app/wiki/wiki-smart.component.ts')(format='.') :marked Wait for the user to stop typing for at least 300 milliseconds ([_debounceTime_](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/debounce.md)). Only changed search values make it through to the service ([_distinctUntilChanged_](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/distinctuntilchanged.md)). - + 我们先等待用户停止输入至少300毫秒 ([debounceTime](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/debounce.md))。 只有当搜索关键字变化的时候,才把它传给服务 @@ -1074,7 +1079,7 @@ block wikipedia-jsonp+ The `WikipediaService` returns a separate observable of string arrays (`Observable`) for each request. There could be multiple requests *in-flight*, all awaiting the server's reply, which means multiple *observables-of-strings* could arrive at any moment in any order. - + `WikipediaService`服务为每个请求返回一个独立的可观察的字符串数组(`Observable`)。 我们可以同时有多个*发送中*的请求,它们都在等服务器的回复, 这意味着多个*可观察的字符串数组*有可能在任何时刻以任何顺序抵达。 @@ -1083,32 +1088,32 @@ block wikipedia-jsonp+ (formerly known as `flatMapLatest`) returns a new observable that combines these `WikipediaService` observables, re-arranges them in their original request order, and delivers to subscribers only the most recent search results. - + [switchMap](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/flatmaplatest.md)(以前叫`flatMapLatest`) 返回一个新的可观察对象,它组合了所有这些“可观察的字符串数组”,重新按照它们的原始请求顺序进行排列,然后把最近的一个搜索结果交付给调用者。 The displayed list of search results stays in sync with the user's sequence of search terms. - + 于是,最终显示的搜索结果列表和用户输入的搜索关键字在顺序上保持了一致。 .l-sub-section :marked You added the `debounceTime`, `distinctUntilChanged`, and `switchMap` operators to the RxJS `Observable` class in `rxjs-operators` as [described above](#rxjs). - + 在[前面提过的](#rxjs)`rxjs-operators`文件中,我们把`debounceTime`、`distinctUntilChanged`和`switchMap`操作符加到了RxJS的`Observable`类中。 a#xsrf .l-main-section :marked ## Guarding against Cross-Site Request Forgery - + ## 预防跨站请求伪造攻击 In a cross-site request forgery (CSRF or XSRF), an attacker tricks the user into visiting a different web page with malignant code that secretly sends a malicious request to your application's web server, 在一个跨站请求伪造攻击(CSRF或XSRF)中,攻击者欺骗用户访问一个不同的网页,它带有恶意代码,秘密向你的应用程序服务器发送恶意请求。 - + The server and client application must work together to thwart this attack. Angular's `Http` client does its part by applying a default `CookieXSRFStrategy` automatically to all requests. @@ -1123,7 +1128,7 @@ a#xsrf `CookieXSRFStrategy`支持常见的反XSRF技术,服务端发送一个随机生成的认证令牌到名为`XSRF-TOKEN`的cookie中。 HTTP客户端使用该令牌的值为所有请求添加一个`X-XSRF-TOKEN`页头。 服务器接受这个cookie和页头,比较它们,只有在它们匹配的时候才处理请求。 - + See the [XSRF topic on the Security page](security.html#xsrf) for more information about XSRF and Angular's `XSRFStrategy` counter measures. 参见[安全章的关于XSRF讨论](security.html#xsrf),学习更多关于XSRF和Angular的`XSRFStrategy`的应对措施。 @@ -1136,7 +1141,7 @@ a#in-mem-web-api ## 附录:《英雄指南》的内存(in-memory)服务器 If the app only needed to retrieve data, you could get the heroes from a `heroes.json` file: - + 如果我们只关心获取到的数据,我们可以告诉Angular从一个`heroes.json`文件中获取英雄列表,就像这样: +makeJson('server-communication/ts/app/heroes.json', null, 'app/heroes.json')(format=".") @@ -1145,12 +1150,12 @@ a#in-mem-web-api You wrap the heroes array in an object with a `data` property for the same reason that a data server does: to mitigate the [security risk](http://stackoverflow.com/questions/3503102/what-are-top-level-json-arrays-and-why-are-they-a-security-risk) posed by top-level JSON arrays. - + 我们把英雄数组包装进一个带`data`属性的对象中,就像一个真正的数据服务器所应该做的那样。 这样可以缓解由顶级JSON数组导致的[安全风险](http://stackoverflow.com/questions/3503102/what-are-top-level-json-arrays-and-why-are-they-a-security-risk)。 :marked You'd set the endpoint to the JSON file like this: - + 我们要像这样把端点设置为这个JSON文件: +makeExample('server-communication/ts/app/toh/hero.service.ts', 'endpoint-json', 'app/toh/hero.service.ts')(format=".") @@ -1160,7 +1165,7 @@ a#in-mem-web-api but since the app can't save changes to a JSON file, it needs a web API server. Because there isn't a real server for this demo, it uses an *in-memory web API simulator* instead. - + 这在*“获取”英雄数据*的场景下确实能工作,但我们还想*保存*数据。我们不能把这些改动保存到JSON文件中,我们需要一个Web API服务器。 在本章中,我们不想惹上配置和维护真实服务器的那些麻烦事。 所以,我们转而使用一种*内存Web API仿真器*代替它。 @@ -1171,7 +1176,7 @@ a#in-mem-web-api It's an optional service in its own `angular-in-memory-web-api` library installed with npm (see `package.json`) and registered for module loading by SystemJS (see `systemjs.config.js`). - + 内存Web API不是Angular内核的一部分。 它是一个可选的服务,来自独立的`angular-in-memory-web-api`库。我们可以通过npm(参见`package.json`)来安装它, 并且通过SystemJS(参见`systemjs.config.js`)把它注册进模块加载器。 @@ -1180,22 +1185,19 @@ a#in-mem-web-api The in-memory web API gets its data from !{_a_ca_class_with} a `createDb()` method that returns a map whose keys are collection names and whose values are !{_array}s of objects in those collections. - + 内存Web API从一个带有`createDb()`方法的自定义类中获取数据,并且返回一个map,它的主键(key)是一组名字,而值(value)是一组与之对应的对象数组。 - + Here's the class for this sample, based on the JSON data: - + 这里是与范例中基于JSON的数据源完成相同功能的类: +makeExample('server-communication/ts/app/hero-data.ts', null, 'app/hero-data.ts')(format=".") :marked Ensure that the `HeroService` endpoint refers to the web API: - + 确保`HeroService`的端点指向了这个Web API: +makeExample('server-communication/ts/app/toh/hero.service.ts', 'endpoint', 'app/toh/hero.service.ts')(format=".") -:marked - Finally, redirect client HTTP requests to the in-memory web API. - - 最后,把来自HTTP客户端的请求重定向到这个内存Web API。 + block redirect-to-web-api :marked Finally, redirect client HTTP requests to the in-memory web API by @@ -1212,25 +1214,25 @@ block redirect-to-web-api Angular's `http` service delegates the client/server communication tasks to a helper service called the `XHRBackend`. - + 这次重定向非常容易配置,这是因为Angular的`http`服务把客户端/服务器通讯的工作委托给了一个叫做`XHRBackend`的辅助服务。 - + Using standard Angular provider registration techniques, the `InMemoryWebApiModule` replaces the default `XHRBackend` service with its own in-memory alternative. At the same time, the `forRoot` method initializes the in-memory web API with the *seed data* from the mock hero dataset. - + 使用标准Angular提供商注册方法,`InMemoryWebApiModule`替代默认的`XHRBackend`服务并使用它自己的内存存储服务。 `forRoot`方法来自模拟的英雄数据集的*种子数据*初始化了这个内存Web API .l-sub-section :marked The `forRoot` method name is a strong reminder that you should only call the `InMemoryWebApiModule` _once_, while setting the metadata for the root `AppModule`. Don't call it again. - + `forRoot`方法的名字告诉我们,应该只在设置根模块`AppModule`时调用`InMemoryWebApiModule`*一次*。不要再次调用它。 - + :marked Here is the final, revised version of app/app.module.ts, demonstrating these steps. - + 下面是修改过的(也是最终的)app/app.module.ts版本,用于演示这些步骤。 +makeExcerpt('app/app.module.ts') @@ -1240,5 +1242,5 @@ block redirect-to-web-api the `XHRBackend` provider of the `InMemoryWebApiModule` supersedes all others. :marked See the full source code in the . - + 要想查看完整的源代码,请参见在线例子。 diff --git a/public/docs/ts/latest/guide/structural-directives.jade b/public/docs/ts/latest/guide/structural-directives.jade index 9a9667b519..7f686cad8f 100644 --- a/public/docs/ts/latest/guide/structural-directives.jade +++ b/public/docs/ts/latest/guide/structural-directives.jade @@ -27,7 +27,7 @@ block includes - [写我们自己的结构型指令](#unless) Try the . - + 试试在线例子 @@ -72,7 +72,6 @@ block includes +makeExample('structural-directives/ts/app/structural-directives.component.html', 'structural-directives')(format=".") - .l-main-section :marked @@ -470,7 +469,7 @@ block unless-intro +makeExample('structural-directives/ts/app/unless.directive.ts', null, 'unless.directive.ts') :marked - Now we add it to the `declarations` array of the AppModule and try it. + Now we add it to the `!{_declsVsDirectives}` !{_array} of the !{_AppModuleVsAppComp} and try it. First we add some test HTML to the template: 现在,我们就来把它加到AppModule的`declarations`数组中,试一试。 diff --git a/public/docs/ts/latest/guide/style-guide.jade b/public/docs/ts/latest/guide/style-guide.jade index 049246afc8..bc9f8aa9c7 100644 --- a/public/docs/ts/latest/guide/style-guide.jade +++ b/public/docs/ts/latest/guide/style-guide.jade @@ -2,16 +2,16 @@ include ../_util-fns :marked Welcome to the Angular Style Guide - + 欢迎光临Angular风格指南 - + ## Purpose ## 目的 Looking for an opinionated guide to Angular syntax, conventions, and application structure? Step right in! This style guide presents our preferred conventions and, as importantly, explains why. - + 如果你在寻找一份关于语法、约定和Angular应用程序的组织结构的风格指南,那你就来对了。 本风格指南提供了我们所提倡的约定,但最重要的是,解释了为什么。 @@ -22,11 +22,11 @@ include ../_util-fns ## 风格词汇 Each guideline describes either a good or bad practice, and all have a consistent presentation. - + 每个指导原则都会描述好的或者坏的做法,所有指导原则都相互呼应,保持一致。 The wording of each guideline indicates how strong the recommendation is. - + 指导原则中使用的词汇表明我们推荐的强度。 .s-rule.do @@ -35,23 +35,23 @@ include ../_util-fns _Always_ might be a bit too strong of a word. Guidelines that literally should always be followed are extremely rare. On the other hand, you need a really unusual case for breaking a *Do* guideline. - + **坚持**意味着总是应该遵循的约定。_总是_可能有点太强。应该_总是_遵循的指导原则非常少见。但是,只有遇到非常不寻常的情况才能打破*坚持*的原则。 .s-rule.consider :marked **Consider** guidelines should generally be followed. - - **考虑**标志着通常应该遵循的指导原则。 - + + **考虑**标志着通常应该遵循的指导原则。 + If you fully understand the meaning behind the guideline and have a good reason to deviate, then do so. Please strive to be consistent. - + 如果你能完全理解指导原则背后的含义,并且很好的理由打破它,那就可以打破该指导原则。但是请保持一致。 .s-rule.avoid :marked **Avoid** indicates something you should almost never do. Code examples to *avoid* have an unmistakeable red header. - + **避免**标志着我们决不应该做的事。需要*避免*的代码范例会有不会被忽视的红色标题。 .l-main-section @@ -60,11 +60,11 @@ include ../_util-fns ## 文件结构约定 Some code examples display a file that has one or more similarly named companion files. (e.g. hero.component.ts and hero.component.html). - + 在一些代码例子中,有的文件拥有一个或多个相似名字的伴随文件。(比如,hero.component.ts和hero.component.html)。 The guideline will use the shortcut `hero.component.ts|html|css|spec` to represent those various files. Using this shortcut makes this guide's file structures easier to read and more terse. - + 本指南将会使用像`hero.component.ts|html|css|spec`的简写来表示上面描述的多个文件,目的是保持本指南的简洁性,增加文件结构描述时的可读性。 .l-main-section @@ -74,45 +74,45 @@ a(id='toc') ## Table of Contents ## 目录 - 1. [Single Responsibility](#single-responsibility) - - 1. [单一职责](#single-responsibility) - + 1. [Single Responsibility](#single-responsibility) + + 1. [单一职责](#single-responsibility) + 1. [Naming](#naming) - - 1. [命名约定](#naming) - + + 1. [命名约定](#naming) + 1. [Coding Conventions](#coding-conventions) - - 1. [代码约定](#coding-conventions) - + + 1. [代码约定](#coding-conventions) + 1. [App Structure and Angular Modules](#app-structure-and-angular-modules) - - 1. [应用程序结构与模块划分](#app-structure-and-angular-modules) - + + 1. [应用程序结构与模块划分](#app-structure-and-angular-modules) + 1. [Components](#components) - - 1. [组件](#components) - + + 1. [组件](#components) + 1. [Directives](#directives) - - 1. [指令](#directives) - + + 1. [指令](#directives) + 1. [Services](#services) - - 1. [服务](#services) - + + 1. [服务](#services) + 1. [Data Services](#data-services) - - 1. [数据服务](#data-services) - + + 1. [数据服务](#data-services) + 1. [Lifecycle Hooks](#lifecycle-hooks) - - 1. [生命周期钩子](#lifecycle-hooks) - + + 1. [生命周期钩子](#lifecycle-hooks) + 1. [Appendix](#appendix) - - 1. [附录](#appendix) + + 1. [附录](#appendix) .l-main-section :marked @@ -121,7 +121,7 @@ a(id='toc') Apply the [Single Responsibility Principle](https://wikipedia.org/wiki/Single_responsibility_principle) to all components, services, and other symbols. This helps make the app cleaner, easier to read and maintain, and more testable. - + 我们遵循[单一职责原则](https://en.wikipedia.org/wiki/Single_responsibility_principle)来创建的所有组件、服务和其它标志等。这样能帮助我们把应用程序弄的干净整洁,易于阅读、维护和测试。 ### Rule of One @@ -131,46 +131,46 @@ a(id='toc') .s-rule.do :marked **Do** define one thing (e.g. service or component) per file. - + **坚持**每个文件只定义一样东西(比如服务或者组件)。 .s-rule.consider :marked **Consider** limiting files to 400 lines of code. - + **考虑**把文件大小限制在400行代码以内。 .s-why :marked **Why?** One component per file makes it far easier to read, maintain, and avoid collisions with teams in source control. - + **为何?**单组件文件非常容易阅读、维护,并能防止在版本控制系统里与团队冲突。 .s-why :marked **Why?** One component per file avoids hidden bugs that often arise when combining components in a file where they may share variables, create unwanted closures, or unwanted coupling with dependencies. - + **为何?**单组件文件可以防止一些隐蔽的程序缺陷,当把多个组件合写在同一个文件中时,可能造成共享变量、创建意外的闭包,或者与依赖之间产生意外耦合等情况。 .s-why.s-why-last :marked **Why?** A single component can be the default export for its file which facilitates lazy loading with the Router. - + **为何?**单独的组件通常是该文件默认的输出,这样就可以利用路由器实现按需加载。 - + :marked The key is to make the code more reusable, easier to read, and less mistake prone. - + 最关键的是,可以增强代码可重用性和阅读性,减少出错的可能性。 The following *negative* example defines the `AppComponent`, bootstraps the app, defines the `Hero` model object, and loads heroes from the server ... all in the same file. *Don't do this*. - + 下面的*负面*例子定义了`AppComponent`,该文件引导了应用程序,定义了`Hero`模型对象,并且从服务器加载了英雄 ... 所有都在发生在同一个文件。 *不要这么做*。 +makeExample('style-guide/ts/01-01/app/heroes/hero.component.avoid.ts', '', 'app/heroes/hero.component.ts')(avoid=1) :marked Better to redistribute the component and supporting activities into their own dedicated files. - + 将组件及其支撑部件重新分配到独立的文件中会更好。 +makeTabs( @@ -192,7 +192,7 @@ a(id='toc') :marked As the app grows, this rule becomes even more important. - + 随着应用程序的成长,本法则会变得越来越重要。 a(href="#toc") Back to top @@ -208,42 +208,42 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** define small functions - + **坚持**定义小函数 .s-rule.consider :marked **Consider** limiting to no more than 75 lines. - + **考虑**限制在75行之内 .s-why :marked **Why?** Small functions are easier to test, especially when they do one thing and serve one purpose. - + **为何?**小函数更易于测试,特别是当它们只做一件事,只为一个目的服务的时候。 .s-why :marked **Why?** Small functions promote reuse. - + **为何?**小函数促进了代码的重用。 .s-why :marked **Why?** Small functions are easier to read. - + **为何?**小函数更加易于阅读。 .s-why :marked **Why?** Small functions are easier to maintain. - + **为何?**小函数更加易于维护。 .s-why.s-why-last :marked **Why?** Small functions help avoid hidden bugs that come with large functions that share variables with external scope, create unwanted closures, or unwanted coupling with dependencies. - + **为何?**小函数帮助避免一些大函数容易产生的那些与外界共享变量、创建意外的闭包或与依赖之间产生意外耦合等隐蔽的错误。 a(href="#toc") Back to top @@ -256,7 +256,7 @@ a(href="#toc") 回到顶部 ## 命名约定 Naming conventions are hugely important to maintainability and readability. This guide recommends naming conventions for the file name and the symbol name. - + 命名约定对维护性和可读性非常重要。本指南为文件和标志命名推荐了一套命名约定。 .l-main-section @@ -269,39 +269,37 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use consistent names for all symbols. - + **坚持**为所有符号使用一致的命名规则。 - + .s-rule.do :marked **Do** follow a pattern that describes the symbol's feature then its type. The recommended pattern is `feature.type.ts`. - + **坚持**遵循同一个模式来描述符号的特性和类型。推荐的模式为`feature.type.ts`。 .s-why :marked - **Why?** Naming conventions help provide a consistent way to find content at a glance. Consistency within the project is vital. Consistency with a team is important. - Consistency across a company provides tremendous efficiency. - - **为何?**命名约定提供了一致的方法来帮助我们一眼锁定内容。在整个项目内保持一致性是至关重要的。在团队内保持一致性也很重要。在公司内部保持一致性可以大幅提高效率。 + **Why?** Naming conventions help provide a consistent way to find content at a glance. Consistency within the project is vital. Consistency with a team is important. Consistency across a company provides tremendous efficiency. + + **为何?**命名约定提供了一致的方法来帮助我们一眼锁定内容。 .s-why :marked **Why?** The naming conventions should simply help find desited code faster and make it easier to understand. - + **为何?**命名约定最直接的目的是:帮我们快速找到代码并让它们更容易理解。 .s-why.s-why-last :marked **Why?** Names of folders and files should clearly convey their intent. For example, `app/heroes/hero-list.component.ts` may contain a component that manages a list of heroes. - + **为何?**目录和文件的名字应该清楚的说明它们的用途。比如`app/heroes/hero-list.component.ts`包含了一个用来维护英雄列表的组件。 a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Separate File Names with Dots and Dashes @@ -312,64 +310,59 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use dashes to separate words in the descriptive name. - + **坚持** 在描述性名字里面,使用横杠来分隔单词。 - .s-rule.do :marked **Do** use dots to separate the descriptive name from the type. - + **坚持**使用点来分隔描述性名字和类型名。 .s-rule.do :marked **Do** use consistent type names for all components following a pattern that describes the component's feature then its type. A recommended pattern is `feature.type.ts`. - + **坚持**对所有组件使用一致的类型命名规则,遵循这个模式:先描述组件的特性,再描述它的类型。推荐的模式为`feature.type.ts`。 - .s-rule.do :marked **Do** use conventional type names including `.service`, `.component`, `.pipe`, `.module`, `.directive`. Invent additional type names if you must but take care not to create too many. - + **坚持**使用惯用的后缀来描述类型,比如`*.service`、`*.component`、`*.pipe`、`.module`、`.directive`。 创建更多类型名,但你必须注意不要创建太多。 - .s-why :marked **Why?** Type names provide a consistent way to quickly identify what is in the file. - + **为何?**类型名字提供一致的方法来快速的识别文件是什么。 - .s-why :marked **Why?** Make it easy to find a specific file type using an editor or IDE's fuzzy search techniques. - - **为何?** 可以让我们利用编辑器或者IDE的模糊搜索功能,很容易的找到特定文件。 + + **为何?** 可以让我们利用编辑器或者IDE的模糊搜索功能,很容易的找到特定文件。 .s-why :marked **Why?** Unabbreviated type names such as `.service` are descriptive and unambiguous. Abbreviations such as `.srv`, `.svc`, and `.serv` can be confusing. - + **为何?** 没有被简写的类型名字比如`.service`很有描述性,不含糊。 简写可能造成混淆,比如`.srv`, `.svc`, 和 `.serv`。 .s-why.s-why-last :marked **Why?** Provides pattern matching for any automated tasks. - + **为何?**与自动化任务的模式匹配。 a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Symbols and File Names @@ -380,38 +373,38 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use consistent names for all assets named after what they represent. - + **坚持**为所有东西使用一致的命名约定:以它们所代表的东西命名。 .s-rule.do :marked **Do** use upper camel case for class names. Match the name of the symbol to the name of the file. - + **坚持**使用大写驼峰命名法来命名所有类名。保持符号的名字与它所在的文件名字相同。 .s-rule.do :marked **Do** append the symbol name with the conventional suffix for a thing of that type (e.g., `Component`, `Directive`, `Module`, `Pipe`, `Service`). - + **坚持**在符号名后面追加约定的类型后缀(比如:`Component`、`Directive`、`Module`、`Pipe`、`Service`)。 .s-rule.do :marked **Do** give the filename the conventional suffix for a file of that type (e.g., `.component.ts`, `.directive.ts`, `.module.ts`, `.pipe.ts`, `.service.ts`). - + **坚持**在文件名后面追加约定的类型后缀(比如`.component.ts`、`.directive.ts`、`.module.ts`、`.pipe.ts`、`.service.ts`)。 .s-why :marked **Why?** Provides a consistent way to quickly identify and reference assets. - + **为何?**提供一种一致的方式,以快速标识和引用资产。 .s-why.s-why-last :marked **Why?** Upper camel case is conventional for identifying objects that can be instantiated using a constructor. - + **为何?**大驼峰命名法是用来识别那些能通过构造函数进行实例化的对象的命名约定。 - var top="vertical-align:top" @@ -419,10 +412,10 @@ table(width="100%") col(width="50%") col(width="50%") tr - th + th p Symbol Name p 符号名 - th + th p File Name p 文件名 tr(style=top) @@ -505,37 +498,37 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use consistent names for all services named after their feature. - + **坚持**使用前后一致的命名规则来命名服务,以它们的特性来命名。 .s-rule.do :marked **Do** use upper camel case for services. - + **坚持**使用大写驼峰命名法来命名服务。 .s-rule.do :marked **Do** suffix services with `Service` when it is not clear what they are (e.g. when they are nouns). - + **坚持**当不能从它们的名字里清楚的看出它们是什么的时候(比如它们的名字是名词时),添加`Service`后缀。 .s-why :marked **Why?** Provides a consistent way to quickly identify and reference services. - + **为何?**提供前后一致的方法来快速识别和引用服务。 .s-why :marked **Why?** Clear service names such as `Logger` do not require a suffix. - + **为何?**清楚的服务名,比如`Logger`不需要后缀。 .s-why.s-why-last :marked **Why?** Service names such as `Credit` are nouns and require a suffix and should be named with a suffix when it is not obvious if it is a service or something else. - + **为何?**如果服务名字是名词时,比如`Credit`,需要一个后缀。当名字不能很明显的标示出它是服务还是其它东西的时候,应该添加后缀。 - var top="vertical-align:top" @@ -543,10 +536,10 @@ table(width="100%") col(width="50%") col(width="50%") tr - th + th p Symbol Name p 符号名 - th + th p File Name p 文件名 tr(style=top) @@ -589,31 +582,31 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** put bootstrapping and platform logic for the app in a file named `main.ts`. - + **坚持**把应用的引导程序和平台相关的逻辑放到名为`main.ts`的文件里。 .s-rule.do :marked **Do** include error handling in the bootstrapping logic. - - **坚持**在“引导”逻辑中包含错误处理代码。 + + **坚持**在“引导”逻辑中包含错误处理代码。 .s-rule.avoid :marked **Avoid** putting app logic in the `main.ts`. Instead consider placing it in a component or service. - + **避免**把应用逻辑放在`main.ts`中,而应该考虑把它们放进组件或服务里。 .s-why :marked **Why?** Follows a consistent convention for the startup logic of an app. - + **为何?**遵循前后一致的约定来处理应用的启动逻辑。 .s-why.s-why-last :marked **Why?** Follows a familiar convention from other technology platforms. - + **为何?**这是从其它技术平台借鉴的一个常用约定。 +makeExample('style-guide/ts/02-05/main.ts', '', 'main.ts') @@ -623,7 +616,6 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Directive Selectors @@ -634,26 +626,25 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** Use lower camel case for naming the selectors of directives. - + **坚持**使用小驼峰命名法来命名指令的选择器。 .s-why :marked **Why?** Keeps the names of the properties defined in the directives that are bound to the view consistent with the attribute names. - + **为何?**保持指令里定义的属性名字与它们绑定的视图HTML属性名字一致。 .s-why.s-why-last :marked **Why?** The Angular HTML parser is case sensitive and will recognize lower camel case. - + **为何?**Angular HTML解析器是大小写敏感的,它识别小写驼峰写法。 a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Custom Prefix for Components @@ -664,39 +655,39 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use a hyphenated, lowercase element selector value (e.g. `admin-users`). - + **坚持**使用带连字符的小写元素选择器的值(比如`admin-users`)。 .s-rule.do :marked **Do** use a custom prefix for a component selector. For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the prefix `admin` represents an admin feature area. - + **坚持**为组件选择器使用自定义前缀。 比如`toh`前缀表示**T**our **o**f **H**eroes(英雄指南),而前缀`admin表示管理特性区。 .s-rule.do :marked **Do** use a prefix that identifies the feature area or the app itself. - + **坚持**使用前缀来识别特性区域或者应用程序本身。 .s-why :marked **Why?** Prevents element name collisions with components in other apps and with native HTML elements. - + **为何?**防止与来自其它应用中的组件和原生HTML元素发生命名冲突。 .s-why :marked **Why?** Makes it easier to promote and share the component in other apps. - + **为何?**把我们的组件推广和共享到其它应用中会更容易。 .s-why.s-why-last :marked **Why?** Components are easy to identify in the DOM. - + **为何?**组件在DOM中更容易被区分出来。 +makeExample('style-guide/ts/02-07/app/heroes/hero.component.avoid.ts', 'example', 'app/heroes/hero.component.ts')(avoid=1) @@ -720,25 +711,25 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use a custom prefix for the selector of directives (e.g, the prefix `toh` from **T**our **o**f **H**eroes). - + **坚持**为指令的选择器使用自定义前缀(比如前缀`toh`来自**T**our **o**f **H**eroes)。 .s-rule.do :marked **Do** spell non-element selectors in lower camel case unless the selector is meant to match a native HTML attribute. - + **坚持**用小驼峰形式拼写非元素选择器,除非该选择器就是要用来匹配某个原生HTML属性的。 .s-why :marked **Why?** Prevents name collisions. - + **为何?**防止名字冲突。 .s-why.s-why-last :marked **Why?** Directives are easily identified. - + **为何?**指令更加容易被识别。 +makeExample('style-guide/ts/02-08/app/shared/validate.directive.avoid.ts', 'example', 'app/shared/validate.directive.ts')(avoid=1) @@ -761,13 +752,13 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use consistent names for all pipes, named after their feature. - + **坚持**为所有管道使用前后一致的命名约定,用它们的特性来命名。 .s-why.s-why-last :marked **Why?** Provides a consistent way to quickly identify and reference pipes. - + **为何?**提供一致的方法快速识别和引用管道。 - var top="vertical-align:top" @@ -775,10 +766,10 @@ table(width="100%") col(width="50%") col(width="50%") tr - th + th p Symbol Name p 符号名 - th + th p File Name p 文件名 tr(style=top) @@ -807,30 +798,31 @@ a(href="#toc") 回到顶部 :marked ### Unit Test File Names ### 单元测试文件名 + #### Style 02-10 #### 风格02-10 .s-rule.do :marked **Do** name test specification files the same as the component they test. - + **坚持**测试规范文件的名字应该和被测试的组件名字一样。 .s-rule.do :marked **Do** name test specification files with a suffix of `.spec`. - + **坚持**测试配置文件命名应该跟随后缀`.spec`。 .s-why :marked **Why?** Provides a consistent way to quickly identify tests. - + **为何?**提供一致的方法来快速识别测试。 .s-why.s-why-last :marked **Why?** Provides pattern matching for [karma](http://karma-runner.github.io/) or other test runners. - + **为何?**提供一个与[karma](http://karma-runner.github.io/)或者其它测试运行器相配的命名模式。 :marked @@ -849,7 +841,7 @@ table(width="100%") td :marked Components - + 组件 td :marked @@ -862,7 +854,7 @@ table(width="100%") td :marked Services - + 服务 td :marked @@ -875,7 +867,7 @@ table(width="100%") td :marked Pipes - + 管道 td :marked @@ -898,19 +890,19 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** name end-to-end test specification files after the feature they test with a suffix of `.e2e-spec`. - + **坚持**端到端测试配置文件应该和它们所测试的特性同名,并加上后缀`.e2e-spec`。 .s-why :marked **Why?** Provides a consistent way to quickly identify end-to-end tests. - + **为何?**提供一致的方法快速识别端到端测试文件。 .s-why.s-why-last :marked **Why?** Provides pattern matching for test runners and build automation. - + **为何?**提供一个与测试运行器和构建自动化相配的模式。 :marked @@ -930,7 +922,7 @@ table(width="100%") td :marked End to End Tests - + 端到端测试 td :marked @@ -952,59 +944,59 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** append the symbol name with the suffix `Module`. - + **坚持**为符号名追加`Module`后缀 .s-rule.do :marked **Do** give the file name the `.module.ts` extension. - + **坚持**为文件名添加`.module.ts`扩展名。 .s-rule.do :marked **Do** name the module after the feature and folder it resides in. - + **坚持**用特性名和所在目录命名模块。 - + .s-why :marked **Why?** Provides a consistent way to quickly identify and reference modules. - + **为何?**提供一个一致的方式来快速的标出和引用模块。 .s-why :marked **Why?** Upper camel case is conventional for identifying objects that can be instantiated using a constructor. - + **为何?**大驼峰命名法是一种命名约定,用来标出可用构造函数实例化的对象。 .s-why.s-why-last :marked **Why?** Easily identifies the module as the root of the same named feature. - + **为何?**很容易就能看出这个模块是同名特性的跟模块。 .s-rule.do :marked **Do** suffix a _RoutingModule_ class name with `RoutingModule`. - + **坚持**为*RoutingModule*类名添加`RoutingModule`后缀。 .s-rule.do :marked **Do** end the filename of a _RoutingModule_ with `-routing.module.ts`. - + **坚持** *RoutingModule*的文件名用`-routing.module.ts`结尾。 .s-why.s-why-last :marked **Why?** A `RoutingModule` is a module dedicated exclusively to configuring the Angular router. A consistent class and file name convention make these modules easy to spot and verify. - + **为何?**`RoutingModule`是一种专门用来配置Angular路由器的模块。 “让类名和文件名保持一致”这项约定可以让这些模块易于跟踪和验证。 - + - var top="vertical-align:top" table(width="100%") col(width="50%") @@ -1064,7 +1056,7 @@ a(href="#toc") 回到顶部 ## 编程约定 Have consistent set of coding, naming, and whitespace conventions. - + 坚持一套前后一致的编程、命名和空格的约定。 .l-main-section @@ -1075,20 +1067,20 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use upper camel case when naming classes. - + **坚持**使用大写驼峰命名法来命名类。 .s-why :marked **Why?** Follows conventional thinking for class names. - + **为何?**遵循类命名传统约定。 .s-why.s-why-last :marked **Why?** Classes can be instantiated and construct an instance. By convention, upper camel case indicates a constructable asset. - + **为何?**类可以被实例化和构造出实例。根据约定,用大写驼峰命名法来标示可被构造出来的东西。 +makeExample('style-guide/ts/03-01/app/core/exception.service.avoid.ts', 'example', 'app/shared/exception.service.ts')(avoid=1) @@ -1101,7 +1093,6 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Constants @@ -1112,33 +1103,33 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** declare variables with `const` if their values should not change during the application lifetime. - + **坚持**用`const`声明变量,除非它们的值在应用的生命周期内会发生变化。 .s-why :marked **Why?** Conveys to readers that the value is invariant. - + **为何?** 告诉读者这个值是不可变的。 .s-why.s-why-last :marked **Why?** TypeScript helps enforce that intent by requiring immediate initialization and by preventing subsequent re-assignment. - + **为何?**TypeScript会要求在声明时立即初始化,并阻止对其再次赋值,以确保达成我们的意图。 - + .s-rule.consider :marked **Consider** spelling `const` variables in lower camel case. - + **考虑** 把常量名拼写为小驼峰格式。 .s-why :marked **Why?** lower camel case variable names (`heroRoutes`) are easier to read and understand than the traditional UPPER_SNAKE_CASE names (`HERO_ROUTES`). - + **为何?**小驼峰变量名(`heroRoutes`)比传统的“大写蛇形命名法”(`HERO_ROUTES`)更容易阅读和理解。 .s-why.s-why-last @@ -1146,14 +1137,14 @@ a(href="#toc") 回到顶部 **Why?** The tradition of naming constants in UPPER_SNAKE_CASE reflects an era before the modern IDEs that quickly reveal the `const` declaration. TypeScript itself prevents accidental reassignment. - + **为何?** 把常量命名为大写蛇形命名法的传统源于现代IDE出现之前,以便阅读时可以快速发现那些`const`定义。 而TypeScript本身就能够防止意外赋值。 - + .s-rule.do :marked **Do** tolerate _existing_ `const` variables that are spelled in UPPER_SNAKE_CASE. - + **坚持** 容许_现存的_`const`变量沿用大写蛇形命名法。 .s-why.s-why-last @@ -1161,7 +1152,7 @@ a(href="#toc") 回到顶部 **Why?** The tradition of UPPER_SNAKE_CASE remains popular and pervasive, especially in third party modules. It is rarely worth the effort to change them or the risk of breaking existing code and documentation. - + **为何?**传统的大写蛇形命名法(UPPER_SNAKE_CASE)仍然很流行、很普遍,特别是在第三方模块中。 修改它们带不来多大价值,同时还会有破坏现有代码和文档的风险。 @@ -1172,7 +1163,6 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Interfaces @@ -1183,44 +1173,44 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** name an interface using upper camel case. - + **坚持**使用大写驼峰命名法来命名接口。 .s-rule.consider :marked **Consider** naming an interface without an `I` prefix. - + **考虑**不要在接口名字前面加`I`前缀。 .s-rule.consider :marked **Consider** using a class instead of an interface. - + **考虑**用类代替接口。 .s-why :marked **Why?** TypeScript guidelines discourage the "I" prefix. - + **为何?**TypeScript指导原则不建议使用“I”前缀。 .s-why :marked **Why?** A class alone is less code than a _class-plus-interface_. - + **为何?**单独一个类的代码量小于*类+接口*。 .s-why :marked **Why?** A class can act as an interface (use `implements` instead of `extends`). - + **为何?**类实际上就是接口(只是要用`implements`代替`extends`而已)。 .s-why.s-why-last :marked **Why?** An interface-class can be a provider lookup token in Angular dependency injection. - + **为何?**在Angular依赖注入系统中,接口类可以作为服务提供商的查阅令牌。 +makeExample('style-guide/ts/03-03/app/core/hero-collector.service.avoid.ts', 'example', 'app/shared/hero-collector.service.ts')(avoid=1) @@ -1233,7 +1223,6 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Properties and Methods @@ -1244,31 +1233,31 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use lower camel case to name properties and methods. - + **坚持**使用小写驼峰命名法来命名属性和方法。 .s-rule.avoid :marked **Avoid** prefixing private properties and methods with an underscore. - + **避免**使用下划线为前缀来命名私有属性和方法。 .s-why :marked **Why?** Follows conventional thinking for properties and methods. - + **为何?**遵循传统属性和方法的命名约定。 .s-why :marked **Why?** JavaScript lacks a true private property or method. - + **为何?**JavaScript不支持真正的私有属性和方法。 .s-why.s-why-last :marked **Why?** TypeScript tooling makes it easy to identify private vs public properties and methods. - + **为何?**TypeScript工具让识别私有或公有属性和方法变得很简单。 +makeExample('style-guide/ts/03-04/app/core/toast.service.avoid.ts', 'example', 'app/shared/toast.service.ts')(avoid=1) @@ -1290,31 +1279,31 @@ a(href="#toc") 回到顶部 .s-rule.consider :marked **Consider** leaving one empty line between third party imports and application imports. - + **坚持**在第三方导入和自己代码的导入之间留一个空行。 .s-rule.consider :marked **Consider** listing import lines alphabetized by the module. - + **考虑**按模块名字的字母顺排列导入行。 .s-rule.consider :marked **Consider** listing destructured imported assets alphabetically. - + **考虑**在解构表达式中按字母顺序排列导入的东西。 .s-why :marked **Why?** The empty line makes it easy to read and locate imports. - + **为何?**空行可以让阅读和定位本地导入变得更加容易。 .s-why.s-why-last :marked **Why?** Alphabetizing makes it easier to read and locate imports. - + **为何?**按字母顺序排列可以让阅读和定位本地导入更加容易。 +makeExample('style-guide/ts/03-06/app/heroes/shared/hero.service.avoid.ts', 'example', 'app/heroes/shared/hero.service.ts')(avoid=1) @@ -1327,36 +1316,33 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ## App Structure and Angular Modules ## 应用程序的结构与Angular模块划分 Have a near-term view of implementation and a long-term vision. Start small but keep in mind where the app is heading down the road. - + 准备一个短期和一个长期的实施方案。从零开始,但要时刻考虑应用程序接下来要走的路。 - All of the app's code goes in a folder named `app`. All feature areas are in their own folder, with their own Angular module. - + 把所有应用程序的源代码都放到名叫`app`的目录里。 所有特性区都在自己的文件夹中,带有他们自己的Angular模块。 - - All content is 1 asset per file. Each component, service, and pipe is in its own file. + + All content is 1 asset per file. Each component, service, and pipe is in its own file. All 3rd party vendor scripts are stored in another folder and not in the `app` folder. You didn't write them and you don't want them cluttering app. Use the naming conventions for files in this guide. - + 所有内容都遵循每个文件单个特性的原则。每个组件、服务和管道都在自己的文件里。 - 所有第三方程序包都被保存到其它目录里而不在`app`目录里,我们不会修改它们,所以不希望它们弄乱我们的应用程序。使用本指南介绍的文件命名约定。 + 所有第三方程序包都被保存到其它目录里而不在`app`目录里,我们不会修改它们,所以不希望它们弄乱我们的应用程序。使用本指南介绍的文件命名约定。 a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### LIFT @@ -1369,14 +1355,13 @@ a(href="#toc") 回到顶部 `I`dentify the code at a glance, keep the `F`lattest structure you can, and `T`ry to be DRY. - - **坚持**组织应用的结构,达到这些目的:快速定位(`L`ocate)代码、一眼识别(`I`dentify)代码、尽量保持扁平结构(`F`lattest)和尝试`T`ry遵循不重复自己DRY - Do Not Repeat Yourself原则。 + **坚持**组织应用的结构,达到这些目的:快速定位(`L`ocate)代码、一眼识别(`I`dentify)代码、尽量保持扁平结构(`F`lattest)和尝试`T`ry遵循不重复自己DRY - Do Not Repeat Yourself原则。 .s-rule.do :marked **Do** define the structure to follow these four basic guidelines, listed in order of importance. - + **坚持**遵循四个基本指导原则来定义文件结构,上面四个基本原则是按重要顺序排列的。 .s-why.s-why-last @@ -1384,7 +1369,7 @@ a(href="#toc") 回到顶部 **Why?** LIFT Provides a consistent structure that scales well, is modular, and makes it easier to increase developer efficiency by finding code quickly. To confirm your intuition about a particular structure, ask: _can I quickly open and start work in all of the related files for this feature_? - + **为何?**LIFT提供了前后一致的结构,它具有扩展性强、模块化的特性。因为容易快速锁定代码,所以提高了开发者的效率。另外,检查应用结构是否合理的方法是问问自己:我们能快速打开与此特性有关的文件并开始工作吗? a(href="#toc") Back to top @@ -1394,14 +1379,14 @@ a(href="#toc") 回到顶部 :marked ### Locate ### 定位 - + #### Style 04-02 #### 风格04-02 .s-rule.do :marked **Do** make locating code intuitive, simple and fast. - + **坚持**直观、简单和快速的定位我们的代码。 .s-why.s-why-last @@ -1411,7 +1396,7 @@ a(href="#toc") 回到顶部 especially when you do not know (or do not remember) the file _names_. Keeping related files near each other in an intuitive location saves time. A descriptive folder structure makes a world of difference to you and the people who come after you. - + **为何?** 要想高效的工作,就必须能迅速找到文件,特别是当不知道(或不记得)文件*名*时。 把相关的文件一起放在一个直观的位置可以节省时间。 @@ -1431,26 +1416,26 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** name the file such that you instantly know what it contains and represents. - + **坚持**命名文件到这个程度:可以从名字立刻知道它包含了什么,代表了什么。 .s-rule.do :marked **Do** be descriptive with file names and keep the contents of the file to exactly one component. - + **坚持**文件名要具有说明性,并保证文件中只包含一个组件。 .s-rule.avoid :marked **Avoid** files with multiple components, multiple services, or a mixture. - + **避免**创建包含很多组件、服务或者混合体的文件。 .s-why.s-why-last :marked **Why?** Spend less time hunting and pecking for code, and become more efficient. Longer file names are far better than _short-but-obscure_ abbreviated names. - + **为何?**花费更少的时间来查找和琢磨代码,就会变得更有效率。 较长的文件名远胜于*较短却容易混淆的*缩写名。 @@ -1459,14 +1444,13 @@ a(href="#toc") 回到顶部 It may be advantageous to deviate from the _one-thing-per-file_ rule when you have a set of small, closely-related features that are better discovered and understood in a single file than as multiple files. Be wary of this loophole. - + 当你有一组小型、紧密相关的特性时,违反*一物一文件*的规则可能会更好,这种情况下单一文件可能会比多个文件更容易发现和理解。注意这个例外。 a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Flat @@ -1477,40 +1461,40 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** keep a flat folder structure as long as possible. - + **坚持**尽可能保持扁平的目录结构。 .s-rule.consider :marked **Consider** creating sub-folders when a folder reaches seven or more files. - + **考虑**当同一目录下达到7个或更多个文件时创建子目录。 .s-rule.consider :marked **Consider** configuring the IDE to hide distracting, irrelevant files such as generated `.js` and `.js.map` files. - + **考虑**配置IDE,以隐藏无关的文件,比如生成出来的`.js`文件和`.js.map`文件等。 s-why.s-why-last :marked **Why?** No one wants to search for a file through seven levels of folders. A flat structure is easy to scan. - + **为何?**没人想要在超过七层的目录中查找文件。扁平的结构有利于搜索。 - + On the other hand, psychologists believe that humans start to struggle when the number of adjacent interesting things exceeds nine. So when a folder has ten or more files, it may be time to create subfolders. - + 另一方面,心理学家们相信, 当关注的事物超过9个时,人类就会开始感到吃力。 所以,当一个文件夹中有10个或更多个文件时,可能就是创建子目录的时候了。 - - Base your decision on your comfort level. + + Base your decision on your comfort level. Use a flatter structure until there is an obvious value to creating a new folder. - + 还是根据你自己的舒适度而定吧。 除非创建新文件夹能有显著的价值,否则尽量使用扁平结构。 @@ -1528,13 +1512,13 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** be DRY (Don't Repeat Yourself) - + **坚持**不要重复自己(DRY) .s-rule.avoid :marked **Avoid** being so DRY that you sacrifice readability. - + **避免**过度DRY,以致牺牲了阅读性。 .s-why.s-why-last @@ -1543,7 +1527,7 @@ a(href="#toc") 回到顶部 That's why its calle _T-DRY_. For example, it's redundant to name a component, `hero-view.component.html` because a component is obviously a view. But if something is not obvious or departs from a convention, then spell it out. - + **为何?**虽然DRY(不要重复你自己)很重要,但如果要以牺牲LIFT的其它原则为代价,那就不值得了。 这也就是为什么它被称为*T-DRY*。 比如,把组件命名为`hero-view.component.html`是多余的,因为组件显然就是一个视图(view)。 @@ -1563,44 +1547,44 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** start small but keep in mind where the app is heading down the road. - + **坚持**从零开始,但要时刻考虑应用程序接下来要走的路。 .s-rule.do :marked **Do** have a near term view of implementation and a long term vision. - + **坚持**有一个短期和一个长期的实施方案。 .s-rule.do :marked **Do** put all of the app's code in a folder named `app`. - + **坚持**把所有源代码都放到名为`app`的目录里。 .s-rule.consider :marked **Consider** creating a folder for a component when is has multiple accompanying files (`.ts`, `.html`, `.css` and `.spec`). - + **坚持**如果组件具有多个相互合作的文件(`.ts`、`.html`、`.css`和`.spec`),那就为它创建一个文件夹。 .s-why :marked **Why?** Helps keep the app structure small and easy to maintain in the early stages, while being easy to evolve as the app grows. - + **为何?**在早期阶段能够帮助保持应用的结构小巧而且易于维护,这样当应用增长时就会更容易进化了。 .s-why.s-why-last :marked **Why?** Components often have four files (e.g. `*.html`, `*.css`, `*.ts`, and `*.spec.ts`) and can clutter a folder quickly. - + **为何?**组件通常有四个文件(例如`*.html`、 `*.css`、 `*.ts` 和 `*.spec.ts`),它们很容易把一个目录弄乱。 a(id='file-tree') :marked Here is a compliant folder and file structure - - 目录和文件结构 + + 目录和文件结构 .filetree .file <project root> @@ -1662,7 +1646,7 @@ a(id='file-tree') another option for small apps is to keep components flat (not in a dedicated folder). This adds up to four files to the existing folder, but also reduces the folder nesting. Whatever you choose, be consistent. - + 把组件放在专用目录中的方式广受欢迎,对于小型应用,还可以保持组件扁平化(而不是放在专用目录中)。 这样会把四个文件放在现有目录中,但是也会减少目录的嵌套。无论你如何选择,请保持一致。 @@ -1670,7 +1654,6 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Folders-by-Feature Structure @@ -1681,59 +1664,60 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** create folders named for the feature area they represent. - + **坚持**根据特性区的名字创建目录。 .s-why :marked **Why?** A developer can locate the code, identify what each file represents at a glance, the structure is as flat as it can be, and there is no repetitive nor redundant names. - + **为何?**开发人员可以定位代码,扫一眼就能知道每个文件代表什么,目录尽可能保持扁平,既没有重复也没有多余的名字。 .s-why :marked **Why?** The LIFT guidelines are all covered. - + **为何?**LIFT原则中包含了所有这些。 .s-why :marked **Why?** Helps reduce the app from becoming cluttered through organizing the content and keeping them aligned with the LIFT guidelines. - + **为何?**通过精心组织内容并让它们遵循LIFT原则,可以避免应用变得杂乱无章。 .s-why :marked **Why?** When there are a lot of files (e.g. 10+), locating them is easier with a consistent folder structure and more difficult in a flat structure. - + **为何?**当有很多文件时(比如10个以上),在“专用目录”型结构中定位它们会比在扁平结构中更容易。 .s-rule.do :marked **Do** create an Angular module for each feature area. - + **坚持**为每个特性区创建一个Angular模块。 .s-why :marked **Why?** Angular modules make it easy to lazy load routable features. - + **为何?**Angular模块能让对可路由的特性进行惰性加载变得更容易。 .s-why.s-why-last :marked **Why?** Angular modules make it easier to isolate, test, and re-use features. - + **为何?**Angular模块能让我们更容易隔离、测试盒复用特性。 .file-tree-reference a(href="#file-tree") Refer here to this Folder and File Structure example - + a(href="#file-tree") 点这里查看目录和文件结构的范例 a(href="#toc") Back to top a(href="#toc") 回到顶部 + :marked .l-main-section :marked @@ -1745,27 +1729,25 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** create an Angular module in the app's root folder (e.g., in `/app`). - + **坚持**在应用的根部创建一个Angular模块(比如`/app`)。 - .s-why :marked **Why?** Every app requires at least one root Angular module. - + **为何?**每个应用都至少需要一个根Angular模块。 - .s-rule.consider :marked **Consider** naming the root module `app.module.ts`. - + **考虑**把根模块命名为`app.module.ts`。 .s-why.s-why-last :marked **Why?** Makes it easier to locate and identify the root module. - + **为何?**能让定位和识别根模块变得更容易。 +makeExample('style-guide/ts/04-08/app/app.module.ts', 'example', 'app/app.module.ts') @@ -1785,61 +1767,61 @@ a(href="#toc") 回到顶部 :marked **Do** create an Angular module for all distinct features in an application (e.g. `Heroes` feature). - + **坚持**为应用中的每个明显的特性创建一个Angular模块。 .s-rule.do :marked **Do** place the feature module in the same named folder as the feature area (.e.g `app/heroes`). - + **坚持**把特性模块放在与特性区同名的目录中(如`app/heroes`)。 .s-rule.do :marked **Do** name the feature module file reflecting the name of the feature area and folder (e.g. `app/heroes/heroes.module.ts`) - + **坚持**特性模块的名字应该能反映出特性区的名字和目录(如`app/heroes/heroes.module.ts`)。 .s-rule.do :marked **Do** name the feature module symbol reflecting the name of the feature area, folder, and file (e.g. `app/heroes/heroes.module.ts` defines `HeroesModule`) - + **坚持**特性模块的符号名应该能反映出特性区、目录和文件的名字(如在`app/heroes/heroes.module.ts`中定义`HeroesModule`)。 .s-why :marked **Why?** A feature module can expose or hide its implementation from other modules. - + **为何?** 特性模块可以对其它模块暴露或隐藏自己的实现。 .s-why :marked **Why?** A feature module identifies distinct sets of related components that comprise the feature area. - + **为何?**特性模块标记出组成该特性分区的相关组件集合。 .s-why :marked **Why?** A feature module can easily be routed to both eagerly and lazily. - + **为何?**特性模块能很容易的被路由器加载 —— 无论使用主动加载还是惰性加载的方式。 .s-why :marked **Why?** A feature module defines clear boundaries between specific functionality and other application features. - + **为何?**特性模块在特定的功能和其它应用特性之间定义了清晰的边界。 .s-why :marked **Why?** A feature module helps clarify and make it easier to assign development responsibilities to different teams. - + **为何?**特性模块帮助澄清开发职责,以便于把这些职责指派给不同的开发组。 .s-why.s-why-last :marked **Why?** A feature module can easily be isolated for testing. - + **为何?**特性模块易于隔离,以便测试。 a(href="#toc") Back to top @@ -1856,19 +1838,19 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** create a feature module named `SharedModule` in a `shared` folder (e.g. `app/shared/shared.module.ts` defines `SharedModule`). - + **坚持**在`shared`目录中创建名叫`SharedModule`的特性模块(比如在`app/shared/shared.module.ts`中定义`SharedModule`)。 .s-rule.do :marked **Do** put common components, directives and pipes that will be used throughout the application by other feature modules in the `SharedModule`, where those assets are expected to share a new instance of themselves (not singletons). - + **坚持**把可能被应用的其它特性模块使用的公共资产(如组件、指令和管道)放在`SharedModule`中,这些资产倾向于共享自己的新实例(而不是单例)。 .s-rule.do :marked **Do** import all modules required by the assets in the `SharedModule` (e.g. `CommonModule` and `FormsModule`). - + **坚持**在`SharedModule`中导入所有模块都需要的资产(比如:`CommonModule`和`FormsModule`)。 .s-why @@ -1876,17 +1858,17 @@ a(href="#toc") 回到顶部 **Why?** `SharedModule` will contain components, directives and pipes that may need features from another common module (e.g. `ngFor` in `CommonModule`). **为何?** `SharedModule`中包含的组件、指令和管道可能需要来自其它公共模块的特性(比如来自`CommonModule`中的`ngFor`指令)。 - + .s-rule.do :marked **Do** declare all components, directives, and pipes in the `SharedModule`. - + **坚持**在`SharedModule`中声明所有组件、指令和管道。 .s-rule.do :marked **Do** export all symbols from the `SharedModule` that other feature modules need to use. - + **坚持**从`SharedModule`中导出其它特性模块所需的全部符号。 .s-why @@ -1894,24 +1876,24 @@ a(href="#toc") 回到顶部 **Why?** `SharedModule` exists to make commonly used components, directives and pipes available for use in the templates of components in many other modules. **为何?** `SharedModule`的存在,能让常用的组件、指令和管道在很多其它模块的组件模板中都自动可用。 - + .s-rule.avoid :marked **Avoid** specifying app-wide singleton providers in a `SharedModule`. Intentional singletons are OK. Take care. - + **避免**在`SharedModule`中指定应用级的单例服务提供商。但如果是故意设计的单例也可以,不过还是要小心。 .s-why :marked **Why?** A lazy loaded feature module that imports that shared module will make its own copy of the service and likely have undesireable results. - + **为何?**惰性加载的特性模块如果导入了这个共享模块,就会创建一份自己的服务副本,这可能会导致意料之外的后果。 .s-why.s-why-last :marked **Why?** You don't want each module to have its own separate instance of singleton services. Yet there is a real danger of that happening if the `SharedModule` provides a service. - + **为何?**对于单例服务,你是不会希望每个模块都有自己的一份单独实例的。 而如果`SharedModule`提供了一个服务,那就会发生这种情况。 @@ -1956,7 +1938,6 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Core Feature Module @@ -1967,44 +1948,44 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** collect single-use classes and hiding their gory details inside `CoreModule`. A simplified root `AppModule` imports `CoreModule` in its capacity as orchestrator of the application as a whole. - + **坚持**把那些“只用一次”的类收集到`CoreModule`中,并且对外隐藏它们的实现细节。简化的`AppModule`会导入`CoreModule`,并且把它作为整个应用的总指挥。 .s-rule.do :marked **Do** create a feature module named `CoreModule` in a `core` folder (e.g. `app/core/core.module.ts` defines `CoreModule`). - + **坚持**在`core`目录下创建一个名叫`CoreModule`的特性模块(比如在`app/core/core.module.ts`中定义`CoreModule`)。 .s-rule.do :marked **Do** put a singleton service whose instance wil be shared throughout the application in the `CoreModule` (e.g. `ExceptionService` and `LoggerService`). - + **坚持**把一个要共享给整个应用的单例服务放进`CoreModule`中(比如`ExceptionService`和`LoggerService`)。 .s-rule.do :marked **Do** import all modules required by the assets in the `CoreModule` (e.g. `CommonModule` and `FormsModule`). - + **坚持**导入`CoreModule`中的资产所需要的全部模块(比如`CommonModule`和`FormsModule`)。 .s-why :marked **Why?** `CoreModule` provides one or more singleton services. Angular registers the providers with the app root injector, making a singleton instance of each service available to any component that needs them, whether that component is eagerly or lazily loaded. - + **为何?** `CoreModule`提供了一个或多个单例服务。Angular使用应用的根注入器注册这些服务提供商,让每个服务的这个单例对象对所有需要它们的组件都是可用的,而不用管该组件是通过主动加载还是惰性加载的方式加载的。 .s-why :marked **Why?** `CoreModule` will contain singleton services. When a lazy loaded module imports these, it will get a new instance and not the intended app-wide singleton. - + **为何?**`CoreModule`将包含一些单例服务。而如果惰性加载模块导入这些服务,它就会得到一个新实例,而不是所期望的全应用级单例。 .s-rule.do :marked **Do** gather application-wide, single use components in the `CoreModule`. Import it once (in the `AppModule`) when the app starts and never import it anywhere else. (e.g. `NavComponent` and `SpinnerComponent`). - + **坚持**把应用级、只用一次的组件收集到`CoreModule`中。 只在应用启动时从`AppModule`中导入它一次,以后再也不要导入它(比如`NavComponent`和`SpinnerComponent`)。 @@ -2013,51 +1994,50 @@ a(href="#toc") 回到顶部 **Why?** Real world apps can have several single-use components (e.g., spinners, message toasts, and modal dialogs) that appear only in the `AppComponent` template. They are not imported elsewhere so they're not shared in that sense. Yet they're too big and messy to leave loose in the root folder. - + **为何?**真实世界中的应用会有很多只用一次的组件(比如:加载动画、消息浮层、模态框等),它们只会在`AppComponent`的模板中出现,而不会出现在其它地方,所以它们没有被共享的价值。 然而它们又太大了,放在根目录中就会显得乱七八糟的。 .s-rule.avoid :marked **Avoid** importing the `CoreModule` anywhere except in the `AppModule`. - + **避免**在`AppModule`之外的任何地方导入`CoreModule`。 .s-why :marked **Why?** A lazily loaded feature module that directly imports the `CoreModule` will make its own copy of services and likely have undesireable results. - + **为何?**如果惰性加载的特性模块直接导入`CoreModule`,就会创建它自己的服务副本,并导致意料之外的后果。 .s-why :marked **Why?** An eagerly loaded feature module already has access to the `AppModule`'s injector, and thus the `CoreModule`'s services. - + **为何?**主动加载的特性模块已经准备好了访问`AppModule`的注入器,因此也能取得`CoreModule`中的服务。 .s-rule.do :marked **Do** export all symbols that from the `CoreModule` that the `AppModule` will import and make available for other feature modules to use. - + **坚持**从`CoreModule`中导出所有符号,`AppModule`会导入它们,并让它们能在所有特性模块中可用。 .s-why :marked **Why?** `CoreModule` exists to make commonly used singleton services available for use in the many other modules. - + **为何?**`CoreModule`的存在就能让常用的单例服务在所有其它模块中可用。 .s-why.s-why-last :marked - **Why?** You wnat the entire app to use the one, singleton instance. + **Why?** You want the entire app to use the one, singleton instance. You don't want each module to have its own separate instance of singleton services. Yet there is a real danger of that happening accidentally if the `CoreModule` provides a service. - + **为何?**你会希望整个应用都使用这个单例服务。 你不会希望每个模块都有这个单例服务的单独的实例。 然而如果`CoreModule`中提供了一个服务,就可能偶尔导致这种后果。 - .filetree .file src .children @@ -2122,36 +2102,35 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Prevent Reimport of Core Module ### 防止多次导入`CoreModule` #### Style 04-12 #### 风格04-12 - - Only the root `AppModule` should import the `CoreModule`. - + + Only the root `AppModule` should import the `CoreModule`. + 应该只有`AppModule`才能导入`CoreModule`。 .s-rule.do :marked **Do** guard against reimporting of `CoreModule` and fail fast by adding guard logic. - + **坚持**防范多次导入`CoreModule`,并通过添加守卫逻辑来尽快失败。 .s-why.s-why :marked **Why?** Guards against reimporting of the `CoreModule`. - + **为何?**守卫可以阻止对`CoreModule`的多次导入。 .s-why.s-why-last :marked **Why?** Guards against creating multiple instances of assets intended to be singletons. - + **为何?**守卫会禁止创建单例服务的多个实例。 - + +makeTabs( ` style-guide/ts/04-12/app/core/module-import-guard.ts, @@ -2159,7 +2138,7 @@ a(href="#toc") 回到顶部 `, `,`, ` - app/core/module-import-guard, + app/core/module-import-guard.ts, app/core/core.module.ts `) :marked @@ -2175,21 +2154,21 @@ a(href="#toc") 回到顶部 #### Style 04-13 #### 样式04-13 A distinct application feature or workflow may be *lazy loaded* or *loaded on demand* rather than when the application starts. - + 某些边界清晰的应用特性或工作流可以做成*惰性加载*或*按需加载*的,而不用总是随着应用启动。 .s-rule.do :marked **Do** put the contents of lazy loaded features in a *lazy loaded folder*. A typical *lazy loaded folder* contains a *routing component*, its child components, and their related assets and modules. - + **坚持**把惰性加载特性下的内容放进*惰性加载目录*中。 典型的*惰性加载目录*包含*路由组件*及其子组件以及与它们有关的那些资产和模块。 .s-why.s-why-last :marked **Why?** The folder makes it easy to identify and isolate the feature content. - + **为何?**这种目录让标识和隔离这些特性内容变得更轻松。 a(href="#toc") Back to top @@ -2206,13 +2185,13 @@ a(href="#toc") 回到顶部 .s-rule.avoid :marked **Avoid** allowing modules in sibling and parent folders to directly import a module in a *lazy loaded feature*. - + **避免**让兄弟模块和父模块直接导入*惰性加载特性*中的模块。 .s-why.s-why-last :marked **Why?** Directly importing and using a module will load it immediately when the intention is to load it on demand. - + **为何?**直接导入并使用此模块会主动加载它,而我们原本的设计意图是按需加载它。 a(href="#toc") Back to top @@ -2222,7 +2201,7 @@ a(href="#toc") 回到顶部 .l-main-section :marked ## Components - + ## 组件 ### Component Selector Naming @@ -2233,13 +2212,13 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use _dashed-case_ or _kebab-case_ for naming the element selectors of components. - + **坚持**使用*中线(dashed)命名法*或*烤串(kebab)命名法*来命名组件中的元素选择器。 .s-why.s-why-last :marked **Why?** Keeps the element names consistent with the specification for [Custom Elements](https://www.w3.org/TR/custom-elements/). - + **为何?**保持元素命名与[自定义元素](https://www.w3.org/TR/custom-elements/)命名规范一致。 +makeExample('style-guide/ts/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts', 'example', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1) @@ -2267,27 +2246,27 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** define components as elements via the selector. - + **坚持**通过选择器把组件定义为元素。 .s-why :marked **Why?** components have templates containing HTML and optional Angular template syntax. They are most associated with putting content on a page, and thus are more closely aligned with elements. - + **为何?**组件有很多包含HTML以及可选Angular模板语法的模板。它们的功能多数都与把内容放进页面有关,而这和HTML元素的设计意图很相似。 .s-why :marked **Why?** A component represents a visual element on the page. Defining the selector as an HTML element tag is consistent with native HTML elements and WebComponents. - + **为何?**组件表示页面上的可视元素。 把该选择器定义成HTML元素标签可以与原生HTML和WebComponent保持一致。 .s-why.s-why-last :marked **Why?** It is easier to recognize that a symbol is a component vs a directive by looking at the template's html. - + **为何?**查看组件是否有模板HTML文件,是最简单的识别一个符号是组件还是指令的方法。 +makeExample('style-guide/ts/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts', 'example', 'app/heroes/hero-button/hero-button.component.ts')(avoid=1) @@ -2318,31 +2297,31 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** extract templates and styles into a separate file, when more than 3 lines. - + **坚持**当超过三行的时候,把模板和样式提取到一个单独的文件。 .s-rule.do :marked **Do** name the template file `[component-name].component.html`, where [component-name] is the component name. - + **坚持**把模板文件命名为`[component-name].component.html`,这里的[component-name]就是组件名。 .s-rule.do :marked **Do** name the style file `[component-name].component.css`, where [component-name] is the component name. - + **坚持**把样式文件命名为`[component-name].component.css`,这里的[component-name]就是组件名。 - + .s-why :marked **Why?** Syntax hints for inline templates in (*.js and *.ts) code files are not supported by some editors. - + **为何?**在(*.js和*.ts)代码里面内联模板时,一些编辑器不支持语法提示。 .s-why.s-why-last :marked **Why?** A component file's logic is easier to read when not mixed with inline template and styles. - + **为何?**当没有与内联模板和样式混合的时候,组件文件里的逻辑更加易于阅读。 +makeExample('style-guide/ts/05-04/app/heroes/heroes.component.avoid.ts', 'example', 'app/heroes/heroes.component.ts')(avoid=1) @@ -2362,7 +2341,6 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Decorate Input and Output Properties Inline @@ -2374,38 +2352,38 @@ a(href="#toc") 回到顶部 :marked **Do** use `@Input` and `@Output` instead of the `inputs` and `outputs` properties of the `@Directive and `@Component` decorators: - + **坚持** 使用`@Directive`和`@Component`装饰器的`@Input`和`@Output`,而非`inputs`和`outputs`属性: .s-rule.do :marked **Do** place the `@Input()` or `@Output()` on the same line as the property they decorate. - + **坚持**把`@Input()`或者`@Output()`放到它们装饰的属性的同一行。 .s-why :marked **Why?** It is easier and more readable to identify which properties in a class are inputs or outputs. - + **为何?**这样易于在类里面识别哪个属性是inputs或outputs。 .s-why :marked **Why?** If you ever need to rename the property or event name associated with `@Input` or `@Output`, you can modify it a single place. - + **为何?** 如果你需要重命名属性或者`@Input`或者`@Output`关联的事件名字,你可以在一个位置修改。 .s-why :marked **Why?** The metadata declaration attached to the directive is shorter and thus more readable. - + **为何?**依附到指令的元数据声明会比较简短,更易于阅读。 .s-why.s-why-last :marked **Why?** Placing the decorator on the same line makes for shorter code and still easily identifies the property as an input or output. - + **为何?**把装饰器放到同一行可以精简代码,同时更易于识别输入或输出属性。 +makeExample('style-guide/ts/05-12/app/heroes/shared/hero-button/hero-button.component.avoid.ts', 'example', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1) @@ -2428,13 +2406,13 @@ a(href="#toc") 回到顶部 .s-rule.avoid :marked **Avoid** renaming inputs and outputs, when possible. - + **避免**重命名输入和输出。 .s-why.s-why-last :marked **Why?** May lead to confusion when the output or the input properties of a given directive are named a given way but exported differently as a public API. - + **为何?**可能导致混乱,造成指令的输入或输出属性的名字与导出的公共API名字不一样。 +makeExample('style-guide/ts/05-13/app/heroes/shared/hero-button/hero-button.component.avoid.ts', 'example', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1) @@ -2455,7 +2433,6 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Member Sequence @@ -2466,20 +2443,20 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** place properties up top followed by methods. - + **坚持**把属性成员放到顶部,方法成员紧随其后。 .s-rule.do :marked **Do** place private members after public members, alphabetized. - + **坚持**先放公共成员,再放私有成员,并按照字母顺序排列。 .s-why.s-why-last :marked **Why?** Placing members in a consistent sequence makes it easy to read and helps instantly identify which members of the component serve which purpose. - + **为何?**把类的成员按照统一的顺序排列,可以让它们更易于阅读,这能帮我们立即识别出组件的哪个成员服务于何种目的(比如是实现还是接口)。 +makeExample('style-guide/ts/05-14/app/shared/toast/toast.component.avoid.ts', 'example', 'app/shared/toast/toast.component.ts')(avoid=1) @@ -2502,37 +2479,37 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** limit logic in a component to only that required for the view. All other logic should be delegated to services. - + **坚持**把组件类中的逻辑限制到只有视图需要的逻辑。所有其它逻辑都应该被放到服务。 .s-rule.do :marked **Do** move reusable logic to services and keep components simple and focused on their intended purpose. - + **坚持**把可以重复使用的逻辑放到服务里,保持组件简单并聚焦于它们预期目的。 .s-why :marked **Why?** Logic may be reused by multiple components when placed within a service and exposed via a function. - + **为何?**当逻辑被放置到服务里并以函数的形式暴露时,它可以被多个组件重复使用。 .s-why :marked **Why?** Logic in a service can more easily be isolated in a unit test, while the calling logic in the component can be easily mocked. - + **为何?**在单元测试时,服务里的逻辑更加容易被隔离。在组件里调用它的逻辑也很容易被模仿Mock。 .s-why :marked **Why?** Removes dependencies and hides implementation details from the component. - + **为何?**从组件移除依赖并隐藏实施细节。 .s-why.s-why-last :marked **Why?** Keeps the component slim, trim, and focused. - + **为何?**保持组件苗条、精简和聚焦 +makeExample('style-guide/ts/05-15/app/heroes/hero-list/hero-list.component.avoid.ts', '', 'app/heroes/hero-list/hero-list.component.ts')(avoid=1) @@ -2545,7 +2522,6 @@ a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ### Don't Prefix Output Properties @@ -2556,26 +2532,26 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** name events without the prefix `on`. - + **坚持**命名事件时,不要带前缀`on`。 .s-rule.do :marked **Do** name event handler methods with the prefix `on` followed by the event name. - + **坚持**把事件处理器方法命名为`on`前缀之后紧跟着事件名。 .s-why :marked **Why?** This is consistent with built-in events such as button clicks. - + **为何?**与内置事件命名一致,比如按钮点击。 .s-why.s-why-last :marked - **Why?** Angular allows for an [alternative syntax](https://angular.io/docs/ts/latest/guide/template-syntax.html#!#binding-syntax) `on-*`. If the event itself was prefixed with `on` this would result in an `on-onEvent` binding expression. - - **为何?**Angular允许[另一种备选语法](https://angular.io/docs/ts/latest/guide/template-syntax.html#!#binding-syntax) `on-*`。如果事件的名字本身带有前缀`on`,那么绑定的表达式可能是`on-onEvent`。 + **Why?** Angular allows for an [alternative syntax](template-syntax.html#binding-syntax) `on-*`. If the event itself was prefixed with `on` this would result in an `on-onEvent` binding expression. + + **为何?**Angular允许[另一种备选语法](template-syntax.html#binding-syntax) `on-*`。如果事件的名字本身带有前缀`on`,那么绑定的表达式可能是`on-onEvent`。 +makeExample('style-guide/ts/05-16/app/heroes/hero.component.avoid.ts', 'example', 'app/heroes/hero.component.ts')(avoid=1) :marked @@ -2597,6 +2573,7 @@ a(href="#toc") 回到顶部 .l-main-section :marked + ### Put Presentation Logic in the Component Class ### 把展示逻辑放到组件类里 #### Style 05-17 #### 风格05-17 @@ -2604,19 +2581,19 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** put presentation logic in the component class, and not in the template. - + **坚持**把表现层逻辑放进组件类中,而不要放在模板里。 .s-why :marked **Why?** Logic will be contained in one place (the component class) instead of being spread in two places. - + **为何?**逻辑应该只出现在一个地方(组件类里)而不应分散在两个地方。 .s-why.s-why-last :marked **Why?** Keeping the component's presentation logic in the class instead of the template improves testability, maintainability, and reusability. - + **为何?**将组件的展示逻辑放到组件类而非模板里,可以增强测试性、维护性和重复使用性。 +makeExample('style-guide/ts/05-17/app/heroes/hero-list/hero-list.component.avoid.ts', 'example', 'app/heroes/hero-list/hero-list.component.ts')(avoid=1) @@ -2634,6 +2611,8 @@ a(href="#toc") 回到顶部 ## Directives ## 指令 +a(href="#toc") Back to top + .l-main-section :marked ### Use Directives to Enhance an Existing Element @@ -2646,17 +2625,17 @@ a(href="#toc") 回到顶部 **Do** use attribute directives when you have presentation logic without a template. **坚持**当你需要有无模板的展示逻辑时,使用属性型指令。 - + .s-why :marked **Why?** Attributes directives don't have an associated template. - + **为何?**属性型指令没有配套的模板。 .s-why.s-why-last :marked **Why?** An element may have more than one attribute directive applied. - + **为何?**一个元素可能使用多个属性型指令。 +makeExample('style-guide/ts/06-01/app/shared/highlight.directive.ts', 'example', 'app/shared/highlight.directive.ts') @@ -2680,13 +2659,13 @@ a(href="#toc") 回到顶部 :marked **Consider** preferring the `@HostListener` and `@HostBinding` to the `host` property of the `@Directive` and `@Component` decorators. - + **考虑**优先使用`@HostListener`和`@HostBinding`,而不是`@Directive`和`@Component`装饰器的`host`属性。 .s-rule.do :marked **Do** be consistent in your choice. - + **坚持**让你的选择保持一致。 .s-why.s-why-last @@ -2695,20 +2674,20 @@ a(href="#toc") 回到顶部 can be modified only in a single place - in the directive's class. If you use the `host` metadata property, you must modify both the property declaration inside the controller, and the metadata associated with the directive. - + **为何?**对于关联到`@HostBinding`的属性或关联到`@HostListener`的方法,要改名时只要在指令类中修改一次就行了。 如果使用元数据属性`host`,你就得在组件类中修改属性声明的同时修改相关的元数据。 +makeExample('style-guide/ts/06-03/app/shared/validator.directive.ts', '', 'app/shared/validator.directive.ts') :marked Compare with the less preferred `host` metadata alternative. - + 与不推荐的方式(`host`元数据)比较一下。 .s-why.s-why-last :marked **Why?** The `host` metadata is only one term to remember and doesn't require extra ES imports. - + **为何?**`host`元数据只是一个便于记忆的名字而已,并不需要额外的ES导入。 +makeExample('style-guide/ts/06-03/app/shared/validator2.directive.ts', '', 'app/shared/validator2.directive.ts') @@ -2731,19 +2710,19 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use services as singletons within the same injector. Use them for sharing data and functionality. - + **坚持**在同一个注入器内,把服务当做单例使用。使用它们来共享数据和功能。 - + .s-why :marked **Why?** Services are ideal for sharing methods across a feature area or an app. - + **为何?**服务是在一个特性范围或一个应用内理想的共享方法的理想载体。 .s-why.s-why-last :marked **Why?** Services are ideal for sharing stateful in-memory data. - + **为何?**服务是共享状态性内存数据的理想方法。 +makeExample('style-guide/ts/07-01/app/heroes/shared/hero.service.ts', 'example', 'app/heroes/shared/hero.service.ts') @@ -2763,25 +2742,25 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** create services with a single responsibility that is encapsulated by its context. - + **坚持**新建单一职责的服务,把它封装在自己的环境内。 .s-rule.do :marked **Do** create a new service once the service begins to exceed that singular purpose. - + **坚持**当服务成长到超出单一用途时,新建一个服务。 .s-why :marked **Why?** When a service has multiple responsibilities, it becomes difficult to test. - + **为何?**当服务有多个职责时,它很难被测试。 .s-why.s-why-last :marked **Why?** When a service has multiple responsibilities, every component or service that injects it now carries the weight of them all. - + **为何?**当某个服务有多个职责时,每个注入它的组件或服务都会承担这些职责的全部开销。 a(href="#toc") Back to top @@ -2803,25 +2782,25 @@ a(href="#toc") 回到顶部 .s-why :marked **Why?** The Angular injector is hierarchical. - + **为何?**Angular注入器是层次性的。 .s-why :marked **Why?** When providing the service to a top level component, that instance is shared and available to all child components of that top level component. - + **为何?**在顶层组件提供服务时,该服务实例在所有该顶级组件的子级组件中可见并共享。 .s-why :marked **Why?** This is ideal when a service is sharing methods or state. - + **为何?**服务是共享方法或状态的理想方法。 .s-why.s-why-last :marked **Why?** This is not ideal when two different components need different instances of a service. In this scenario it would be better to provide the service at the component level that needs the new and separate instance. - + **为何?**当不同的两个组件需要一个服务的不同的实例时,上面的方法这就不理想了。在这种情况下,我们最好在需要崭新和单独服务实例的组件里提供服务。 +makeTabs( @@ -2846,19 +2825,19 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use the `@Injectable` class decorator instead of the `@Inject` parameter decorator when using types as tokens for the dependencies of a service. - + **坚持**当使用类型作为令牌来注入服务的依赖时,使用`@Injectable`类装饰器,而非`@Inject`参数装饰器。 .s-why :marked **Why?** The Angular DI mechanism resolves all dependencies of services based on their types declared with the services' constructors. - + **为何?**Angular的DI机制会基于在服务的构造函数中所声明的类型来解析这些服务的依赖。 .s-why.s-why-last :marked **Why?** When a service accepts only dependencies associated with type tokens, the `@Injectable()` syntax is much less verbose compared to using `@Inject()` on each individual constructor parameter. - + **为何?**当服务只接受类型令牌相关的依赖时,比起在每个构造函数参数上使用`@Inject()`,`@Injectable()`的语法简洁多了。 +makeExample('style-guide/ts/07-04/app/heroes/shared/hero-arena.service.avoid.ts', 'example', 'app/heroes/shared/hero-arena.service.ts')(avoid=1) @@ -2874,7 +2853,7 @@ a(href="#toc") 回到顶部 .l-main-section :marked ## Data Services - ## 数据服务 + ## 数据服务 ### Separate Data Calls ### 分离数据调用 @@ -2884,45 +2863,44 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** refactor logic for making data operations and interacting with data to a service. - + **坚持**把数据操作和数据互动重构到服务里。 .s-rule.do :marked **Do** make data services responsible for XHR calls, local storage, stashing in memory, or any other data operations. - + **坚持**让数据服务来负责XHR调用、本地储存、内存储存或者其它数据操作。 .s-why :marked - **Why?** The component's responsibility is for the presentation and gathering of information for the view. It should not care how it gets the data, just that it knows who to ask for it. Separating the data services moves the logic on how to get it to the data service, and lets the component be simpler and more focused on the view. - + **Why?** The component's responsibility is for the presentation and gathering of information for the view. It should not care how it gets the data, just that it knows who to ask for it. Separating the data services moves the logic on how to get it to the data service, and lets the component be simpler and more focused on the view. + **为何?**组件的职责是为视图展示或收集信息。它不应该理会如何得到数据,它只需要知道向谁要数据。把如何取得数据的逻辑移动到数据服务里,简化了组件,让其聚焦于视图。 .s-why :marked **Why?** This makes it easier to test (mock or real) the data calls when testing a component that uses a data service. - + **为何?**在测试使用数据服务的组件时,可以让数据调用更容易被测试(模仿或者真实)。 .s-why.s-why-last :marked **Why?** Data service implementation may have very specific code to handle the data repository. This may include headers, how to talk to the data, or other services such as `Http`. Separating the logic into a data service encapsulates this logic in a single place hiding the implementation from the outside consumers (perhaps a component), also making it easier to change the implementation. - + **为何?**数据服务的实现可能有非常具体的代码来处理数据仓库,包括数据头(headers)、如何与数据交谈或者其它服务(比如`Http`)。把逻辑分离到数据服务可以把该逻辑封装到一个地方,对外部使用者(比如组件)隐藏具体的实施细节。 a(href="#toc") Back to top a(href="#toc") 回到顶部 - .l-main-section :marked ## Lifecycle Hooks ## 生命周期钩子 Use Lifecycle Hooks to tap into important events exposed by Angular. - + 使用生命周期钩子来介入到Angular暴露的重要事件里。 a(href="#toc") Back to top @@ -2939,14 +2917,14 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** implement the lifecycle hook interfaces. - + **坚持**实现生命周期钩子接口。 .s-why.s-why-last :marked **Why?** Strongly-typed method signatures. The compiler and editor can call out misspellings. - + **为何?**如果使用强类型的方法签名,那么编译器和编辑器可以帮你揪出拼写错误。 +makeExample('style-guide/ts/09-01/app/heroes/shared/hero-button/hero-button.component.avoid.ts', 'example', 'app/heroes/shared/hero-button/hero-button.component.ts')(avoid=1) @@ -2965,7 +2943,7 @@ a(href="#toc") 回到顶部 ## 附录 Useful tools and tips for Angular. - + 有用的Angular工具和小提示 a(href="#toc") Back to top @@ -2982,13 +2960,13 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use [codelyzer](https://www.npmjs.com/package/codelyzer) to follow this guide. - + **坚持**使用[codelyzer](https://www.npmjs.com/package/codelyzer)来实施本指南。 .s-rule.consider :marked **Consider** adjusting the rules in codelyzer to suit your needs. - + **考虑**调整codelyzer的规则来满足你的需求。 a(href="#toc") Back to top @@ -3005,7 +2983,7 @@ a(href="#toc") 回到顶部 .s-rule.do :marked **Do** use file templates or snippets to help follow consistent styles and patterns. Here are templates and/or snippets for some of the web development editors and IDEs. - + **坚持**使用文件模板或代码片段来帮助实现一致的风格和模式。下面是为一些网络开发编辑器和IDE准备的模板和/或代码片段: .s-rule.consider @@ -3015,21 +2993,33 @@ a(href="#toc") 回到顶部 **考虑** 使用[Atom](https://atom.io/)的[代码片段](https://atom.io/packages/angular-2-typescript-snippets)来实施本风格指南。 **Consider** using [snippets](https://github.com/orizens/sublime-angular2-snippets) for [Sublime Text](http://www.sublimetext.com/) that follow these styles and guidelines. - + **考虑** 使用[Sublime Text](http://www.sublimetext.com/)的[代码片段](https://github.com/orizens/sublime-angular2-snippets)来实施本风格指南。 **Consider** using [snippets](https://github.com/mhartington/vim-angular2-snippets) for [Vim](http://www.vim.org/) that follow these styles and guidelines. - + **考虑** 使用[Vim](http://www.vim.org/)的[代码片段](https://github.com/mhartington/vim-angular2-snippets)来实施本风格指南。 - + **Consider** using [snippets](https://marketplace.visualstudio.com/items?itemName=johnpapa.Angular2) for [Visual Studio Code](https://code.visualstudio.com/) that follow these styles and guidelines. - + **考虑**使用[Visual Studio Code](https://code.visualstudio.com/)的[代码片段](https://marketplace.visualstudio.com/items?itemName=johnpapa.Angular2)来实施本风格指南。 - + Use Extension + **Consider** using [snippets](https://atom.io/packages/angular-2-typescript-snippets) for [Atom](https://atom.io/) that follow these styles and guidelines. + + **考虑**使用[Atom](https://atom.io/)的[代码片断](https://atom.io/packages/angular-2-typescript-snippets)来实施本风格指南。 + + **Consider** using [snippets](https://github.com/orizens/sublime-angular2-snippets) for [Sublime Text](http://www.sublimetext.com/) that follow these styles and guidelines. + + **考虑**使用[Sublime Text](http://www.sublimetext.com/)的[代码片断](https://github.com/orizens/sublime-angular2-snippets)来实施本风格指南。 + + **Consider** using [snippets](https://github.com/mhartington/vim-angular2-snippets) for [Vim](http://www.vim.org/) that follow these styles and guidelines. + + **考虑**使用[Vim](http://www.vim.org/)的[代码片断](https://github.com/mhartington/vim-angular2-snippets)来实施本风格指南。 + a(href="#toc") Back to top a(href="#toc") 回到顶部 diff --git a/public/docs/ts/latest/guide/template-syntax.jade b/public/docs/ts/latest/guide/template-syntax.jade index 3910b85407..5bf4331617 100644 --- a/public/docs/ts/latest/guide/template-syntax.jade +++ b/public/docs/ts/latest/guide/template-syntax.jade @@ -73,9 +73,9 @@ p. .l-main-section :marked ## HTML - + ## HTML - + HTML is the language of the Angular template. Our [QuickStart](../quickstart.html) application has a template that is pure HTML: HTML是Angular模板的“语言”。我们的[“快速起步”](../quickstart.html)应用就有一个模板是纯HTML的: @@ -358,7 +358,7 @@ block template-expressions-cannot :marked Like template expressions, template *statements* use a language that looks like #{_JavaScript}. The template statement parser is different than the template expression parser and - specifically supports both basic assignment (`=`) and chaining expressions + specifically supports both basic assignment (`=`) and chaining expressions (with !{__chaining_op}). 和模板表达式一样,模板*语句*也是一个一个看起来很像JavaScript的语言。 @@ -702,7 +702,7 @@ table 这个目标可能是(元素|组件|指令)的Property、(元素|组件|指令)的事件,或(极少数情况下)一个Attribute名。 下面是的汇总表: -// If you update this table, UPDATE it in Dart & JS, too. +//- If you update this table, UPDATE it in Dart & JS, too.
    table tr @@ -839,8 +839,8 @@ table If we must read a target element property or call one of its methods, we'll need a different technique. See the API reference for - [viewChild](../api/core/index/ViewChild-decorator.html) and - [contentChild](../api/core/index/ContentChild-decorator.html). + [ViewChild](../api/core/index/ViewChild-decorator.html) and + [ContentChild](../api/core/index/ContentChild-decorator.html). 如果我们不得不读取目标元素上的属性或调用它的某个方法,我们得用另一种技术。 参见API参考手册中的[viewChild](../api/core/index/ViewChild-var.html)和 @@ -993,7 +993,7 @@ a(id="one-time-initialization") 我们建议建立组织级的代码风格规定,然后选择一种形式,既能遵循规则,又能让手头的任务做起来更自然。 :marked - #### Content Security + #### Content security #### 内容安全 Imagine the following *malicious content*. @@ -1006,8 +1006,7 @@ a(id="one-time-initialization") nor property binding. 幸运的是,Angular数据绑定对危险HTML有防备。在显示它们之前,它对内容先进行*消毒*。不管是插值表达式还是属性绑定,都**不会**允许带有script标签的HTML泄漏到浏览器中。 - -+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-vs-interpolation-sanitization')(format=".") ++makeExample('template-syntax/ts/app/app.component.html', 'property-binding-vs-interpolation-sanitization')(format=".") :marked Interpolation handles the script tags differently than property binding but both approaches render the content harmlessly. @@ -1019,22 +1018,17 @@ figure.image-display .l-main-section :marked - ## Attribute, Class, and Style Bindings - - ## Attribute、Class和Style绑定 - + ## Attribute, class, and style bindings + ## attribute、class和style绑定 The template syntax provides specialized one-way bindings for scenarios less well suited to property binding. 模板语法为那些不太适合使用属性绑定的场景提供了专门的单向数据绑定形式。 - ### Attribute Binding - + ### Attribute binding ### Attribute绑定 - We can set the value of an attribute directly with an **attribute binding**. 我们可以通过**Attribute绑定**来直接设置Attribute的值。 - .l-sub-section :marked This is the only exception to the rule that a binding sets a target property. This is the only binding that creates and sets an attribute. @@ -1116,8 +1110,8 @@ code-example(format="nocode"). Attribute绑定的主要用例之一是设置ARIA Attribute(译注:ARIA指可访问性,用于给残障人士访问互联网提供便利),就像这个例子中一样: +makeExample('template-syntax/ts/app/app.component.html', 'attrib-binding-aria')(format=".") :marked - ### Class Binding - + ### Class binding + ### CSS类绑定 We can add and remove CSS class names from an element’s `class` attribute with @@ -1143,9 +1137,6 @@ code-example(format="nocode"). 我们可以把它改写为一个绑定到所需CSS类名的绑定;这是一个或者全有或者全无的替换型绑定(译注:即当badCurly有值时class这个Attribute设置的内容会被完全覆盖)。 +makeExample('template-syntax/ts/app/app.component.html', 'class-binding-2')(format=".") -block dart-class-binding-bug - //- N/A - :marked Finally, we can bind to a specific class name. Angular adds the class when the template expression evaluates to #{_truthy}. @@ -1163,8 +1154,8 @@ block dart-class-binding-bug 虽然这是一个切换单一类名的好办法,但我们通常更喜欢使用[NgClass指令](#ngClass)来同时管理多个类名。 :marked - ### Style Binding - + ### Style binding + ### 样式绑定 We can set inline styles with a **style binding**. @@ -1207,9 +1198,9 @@ block style-property-name-dart-diff .l-main-section :marked ## Event binding - + ## 事件绑定 - + The bindings we’ve met so far flow data in one direction: **from a component to an element**. 我们前面遇到过的那些绑定的数据流都是单向的:**从组件到元素**。 @@ -1240,9 +1231,9 @@ block style-property-name-dart-diff :marked ### Target event - + ### 目标事件 - + A **name between parentheses** — for example, `(click)` — identifies the target event. In the following example, the target is the button’s click event. @@ -1268,7 +1259,7 @@ block style-property-name-dart-diff [别名input/output属性](#aliasing-io)章节有更多关于该`myClick`指令的解释。 :marked - If the name fails to match element event or output property of a known directive, + If the name fails to match an element event or an output property of a known directive, Angular reports an “unknown directive” error. 如果这个名字没能匹配到元素事件或已知指令的输出型属性,Angular就会报“未知指令”错误。 @@ -1321,10 +1312,9 @@ block style-property-name-dart-diff - - ### Custom Events with EventEmitter - - ### 使用EventEmitter实现自定义事件 + ### Custom events with *EventEmitter* + + ### 使用*EventEmitter*实现自定义事件 Directives typically raise custom events with an Angular [EventEmitter](../api/core/index/EventEmitter-class.html). The directive creates an `EventEmitter` and exposes it as a property. @@ -1354,9 +1344,9 @@ block style-property-name-dart-diff :marked The component defines a `deleteRequest` property that returns an `EventEmitter`. - When the user clicks *delete*, the component invokes the `delete()` method, + When the user clicks *delete*, the component invokes the `delete()` method, telling the `EventEmitter` to emit a `Hero` object. - + 组件定义了一个`deleteRequest`属性,它是一个`EventEmitter`实例。(译注:`deleteRequest`属性是导出Output属性,是组件与父级组件交互的主要方式之一。参见[输入和输出属性](#input-and-output-properties)和[父组件监听子组件的事件](docs/ts/latest/cookbook/component-communication.html#!#child-to-parent)。我们需要用`@Output()`来装饰它,或者把它添加到组件元数据的`outputs`数组中,它才能在父级组件可见。) 当用户点击*删除*时,组件会调用`delete()`方法,这个方法告诉`EventEmitter`,发出一个`Hero`对象。 @@ -1388,7 +1378,7 @@ block style-property-name-dart-diff 这些变更通过系统进行扩散,并最终显示到当前以及其它视图中。 这都是好事。 -// +//- :marked ### Event bubbling and propagation [TODO: reinstate this section when it becomes true] Angular invokes the event-handling statement if the event is raised by the current element or one of its child elements. @@ -1418,32 +1408,33 @@ block style-property-name-dart-diff .l-main-section :marked ## Two-way binding - + ## 双向数据绑定 - + We often want to both display a data property and update that property when the user makes changes. - + 我们经常需要显示数据属性,并在用户作出更改时,更新数据属性及其显示。 On the element side that takes a combination of setting a specific element property and listening for an element change event. - + 在元素层面上,既要设置元素属性,又要监听元素事件变化。 Angular offers a special _two-way data binding_ syntax for this purpose, **`[(x)]`**. The `[(x)]` syntax combines the brackets - of _Property Binding_, `[x]`, with the parentheses of _Event Binding_, `(x)`. - + of _property binding_, `[x]`, with the parentheses of _event binding_, `(x)`. + Angular为此提供一种特殊的_双向数据绑定_语法:**`[(x)]`**。 `[(x)]`语法结合了_属性绑定_的方括号`[x]`和_事件绑定_的圆括号`(x)`。 - + .callout.is-important header [( )] = banana in a box - header [( )] = 盒子里的香蕉 + header [( )] = 盒子里的香蕉 :marked Visualize a *banana in a box* to remember that the parentheses go _inside_ the brackets. 想象*盒子里的香蕉*来记住方括号套圆括号。 + :marked The `[(x)]` syntax is easy to demonstrate when the element has a settable property called `x` and a corresponding event named `xChange`. @@ -1453,7 +1444,8 @@ block style-property-name-dart-diff 当一个元素拥有可以设置的属性`x`和对应的事件`xChange`时,`[(x)]`语法是最容易被解释的。 下面的`SizerComponent`符合这个模式。它有`size`属性和伴随的`sizeChange`事件: -+makeExample('template-syntax/ts/app/sizer.component.ts', null, 'app/sizer.component.ts') ++makeExample('app/sizer.component.ts') + :marked The initial `size` is an input value from a property binding. Clicking the buttons increases or decreases the `size`, within min/max values constraints, @@ -1463,15 +1455,17 @@ block style-property-name-dart-diff 点击按钮,在最大/最小值范围限制内增加或者减少`size`。 然后用调整后的`size`触发`sizeChange`事件。 - Here's an example in which the `AppComponent.fontSize` is two-way bound to the `SizerComponent`: + Here's an example in which the `AppComponent.fontSizePx` is two-way bound to the `SizerComponent`: 下面的例子中,`AppComponent.fontSize`被双向绑定到`SizerComponent`: -+makeExample('template-syntax/ts/app/app.component.html', 'two-way-1')(format=".") + ++makeExcerpt('app/app.component.html', 'two-way-1', '') + :marked - The `AppComponent.fontSize` establishes the initial `SizerComponent.size` value. - Clicking the buttons updates the `AppComponent.fontSize` via the two-way binding. - The revised `AppComponent.fontSize` value flows through to the _style_ binding, making the displayed text bigger or smaller. - Try it in the live example. + The `AppComponent.fontSizePx` establishes the initial `SizerComponent.size` value. + Clicking the buttons updates the `AppComponent.fontSizePx` via the two-way binding. + The revised `AppComponent.fontSizePx` value flows through to the _style_ binding, making the displayed text bigger or smaller. + Try it in the . `AppComponent.fontSize`赋予`SizerComponent.size`初始值。点击按钮通过双向绑定更新`AppComponent.fontSize`。 被修改的`AppComponent.fontSize`通过_样式_绑定,改变文本的显示大小。 @@ -1482,10 +1476,12 @@ block style-property-name-dart-diff 双向绑定语法实际上是_属性_绑定和_事件绑定_的语法糖。 Angular将`SizerComponent`的绑定分解成这样: -+makeExample('template-syntax/ts/app/app.component.html', 'two-way-2')(format=".") + ++makeExcerpt('app/app.component.html', 'two-way-2', '') + :marked The `$event` variable contains the payload of the `SizerComponent.sizeChange` event. - Angular assigns the `$event` value to the `AppComponent.fontSize` when the user clicks the buttons. + Angular assigns the `$event` value to the `AppComponent.fontSizePx` when the user clicks the buttons. `$event`变量包含了`SizerComponent.sizeChange`事件的有效荷载。 当用户点击按钮时,Angular将`$event`赋值给`AppComponent.fontSize`。 @@ -1521,18 +1517,15 @@ a#ngModel +ifDocsFor('ts|js') .callout.is-important - header - :marked - FormsModule is Required to use ngModel - - 要使用ngModel,必须导入FormsModule。 + header FormsModule is Required to use ngModel + header 要使用ngModel,必须导入FormsModule :marked Before we can use the `ngModel` directive in a two-way data binding, we must import the `FormsModule` and add it to the Angular module's `imports` list. Learn more about the `FormsModule` and `ngModel` in the [Forms](../guide/forms.html#ngModel) chapter. - - 要使用`ngModel`做双向数据绑定,得先把`FormsModule`导入我们的模块并把它加入`NgModule`装饰器的`imports`数组。 + + 要使用`ngModel`做双向数据绑定,得先把`FormsModule`导入我们的模块并把它加入`NgModule`装饰器的`imports`数组。 要学习关于`FormsModule`和`ngModel`的更多知识,参见[表单](../guide/forms.html#ngModel)一章。 :marked @@ -1543,9 +1536,9 @@ a#ngModel :marked ### Inside `[(ngModel)]` - + ### `[(ngModel)]`内幕 - + Looking back at the `firstName` binding, it's important to note that we could have achieved the same result with separate bindings to the `` element's `value` property and `input` event. @@ -1571,7 +1564,7 @@ a#ngModel listens for changes to the element's value. `ngModel`数据属性设置元素的`value`属性,并为元素`value`的变化而监听`ngModelChange`事件属性。 - + The details are specific to each kind of element and therefore the `NgModel` directive only works for specific form elements, such as the input text box, that are supported by a [ControlValueAccessor](../api/forms/index/ControlValueAccessor-interface.html). @@ -1583,12 +1576,12 @@ a#ngModel 除非写一个合适的*值访问器*,否则我们不能把`[(ngModel)]`用在我们自己的自定义组件上。但*值访问器*技术超出了本章的范围。 对于不能控制其API的Angular组件或者Web组件,我们可能需要为其添加合适的*value accessor*。 - + It's completely unnecessary for an Angular component that we _do_ control ... because we can name the value and event properties to suit Angular's basic [two-way binding syntax](#two-way) and skip `NgModel` altogether. 但是对于我们能控制的Angular组件来说,这么做就完全没有必要了。因为我们可以指定值和事件属性名字来进行基本的Angular[双向绑定语法](#two-way),完全不用`NgModel`。 - + :marked Separate `ngModel` bindings is an improvement over binding to the element's native properties. We can do better. @@ -1619,7 +1612,7 @@ a#ngModel 下面是实际操作中的所有变体形式,包括这个大写版本: figure.image-display - img(src='/resources/images/devguide/template-syntax/ng-model-anim.gif' alt="NgModel variations") + img(src='/resources/images/devguide/template-syntax/ng-model-anim.gif' alt="NgModel variations") .l-main-section :marked @@ -1927,10 +1920,9 @@ block dart-no-truthy-falsey 赋值给`*ngFor`的字符串并不是一个[模板表达式](#template-expressions)。 它是一个*微语法* —— 由Angular自己解释的小型语言。在这个例子中,字符串`"let hero of heroes"`的含义是: - >*Take each hero in the `heroes` array, store it in the local `hero` variable, and make it available to the templated HTML - for each iteration.* + > *Take each hero in the `heroes` #{_array}, store it in the local `hero` variable, and make it available to the templated HTML for each iteration.* - >*取出`heroes`数组中的每个英雄,把它存在一个局部变量`hero`中,并且在每个迭代中让它对模板HTML可用* + > *取出`heroes`数组中的每个英雄,把它存在一个局部变量`hero`中,并且在每个迭代中让它对模板HTML可用* Angular translates this instruction into a new set of elements and bindings. @@ -1949,7 +1941,7 @@ block dart-no-truthy-falsey .alert.is-critical :marked - A template input variable is **not** the same as a [template reference variable](#ref-vars)! + A template input variable is **not** the same as a [template reference variable](#ref-vars)! 模板输入变量和[模板引用变量](#ref-vars)**不是**一回事! @@ -2042,10 +2034,8 @@ figure.image-display .l-main-section :marked - ## `*` and <template> - - ## `*`与<template> - + ## * and <template> + ## *与<template> When we reviewed the `NgFor`, `NgIf`, and `NgSwitch` built-in directives, we called out an oddity of the syntax: the asterisk (`*`) that appears before the directive names. 当我们审视`NgFor`、`NgIf`和`NgSwitch`内置指令时,我们使用了一种古怪的语法:出现在指令名称前面的星号(`*`)。 @@ -2079,7 +2069,7 @@ figure.image-display :marked The `currentHero` is referenced twice, first as the true/false condition for `NgIf` and again as the actual hero passed into the `HeroDetailComponent`. - + `currentHero`被引用了两次,第一次是作为`NgIf`的真/假条件,第二次把实际的hero值传给了`HeroDetailComponent`。 The first expansion step transports the `ngIf` (without the `*` prefix) and its contents @@ -2100,14 +2090,14 @@ figure.image-display block remember-the-brackets .callout.is-critical - header Remember the brackets! - header 别忘了括号! + header Remember the brackets! + header 别忘了括号! :marked Don’t make the mistake of writing `ngIf="currentHero"`! - That syntax assigns the *string* value "currentHero" to `ngIf`. - In JavaScript a non-empty string is a truthy value, so `ngIf` would always be + That syntax assigns the *string* value `"currentHero"` to `ngIf`. + In JavaScript a non-empty string is a truthy value, so `ngIf` would always be `true` and Angular would always display the `hero-detail` - ... even when there is no `currentHero`! + … even when there is no `currentHero`! 不要误写为`ngIf="currentHero"`! 这种语法会把一个字符串"currentHero"赋值给`ngIf`。 @@ -2117,7 +2107,7 @@ block remember-the-brackets ### Expanding `*ngSwitch` ### 展开`*ngSwitch` - + A similar transformation applies to `*ngSwitch`. We can unfold the syntax ourselves. Here's an example, first with `*ngSwitchCase` and `*ngSwitchDefault` and then again with `