From ccdc8c0cec429dc6b636cb97fd7a6e4e3a32bc75 Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Wed, 10 Aug 2016 08:00:05 -0700 Subject: [PATCH 001/247] chore(pipes): disable broken e2e tests (#2068) --- public/docs/_examples/pipes/e2e-spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/docs/_examples/pipes/e2e-spec.ts b/public/docs/_examples/pipes/e2e-spec.ts index 01c9e5fd13..5f9c4607dc 100644 --- a/public/docs/_examples/pipes/e2e-spec.ts +++ b/public/docs/_examples/pipes/e2e-spec.ts @@ -64,7 +64,7 @@ describe('Pipes', function () { }); - it('should support flying heroes (pure) ', function () { + xit('should support flying heroes (pure) ', function () { let nameEle = element(by.css('flying-heroes input[type="text"]')); let canFlyCheckEle = element(by.css('flying-heroes #can-fly')); let mutateCheckEle = element(by.css('flying-heroes #mutate')); @@ -95,7 +95,7 @@ describe('Pipes', function () { }); - it('should support flying heroes (impure) ', function () { + xit('should support flying heroes (impure) ', function () { let nameEle = element(by.css('flying-heroes-impure input[type="text"]')); let canFlyCheckEle = element(by.css('flying-heroes-impure #can-fly')); let mutateCheckEle = element(by.css('flying-heroes-impure #mutate')); From 2fd162425da9899ba961b5405ef585cf88b71cd6 Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Wed, 10 Aug 2016 10:36:23 -0700 Subject: [PATCH 002/247] chore(dart): api doc builder enhancements (#2050) - #2049, support ng.io doc relative links and code-regions - Change dartdoc output folder to `docs/api` (from `doc/api`). --- gulpfile.js | 24 ++++++++++------ tools/api-builder/dart-package/test.js | 2 +- tools/dart-api-builder/dab.js | 40 ++++++++++++++++++++++---- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index c6e15ae13f..063669f2e9 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -604,20 +604,19 @@ gulp.task('build-dart-cheatsheet', [], function() { gulp.task('dartdoc', ['pub upgrade'], function() { const ngRepoPath = ngPathFor('dart'); - if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, 'doc'))) { - gutil.log('Skipping dartdoc: --fast flag enabled and "doc" dir exists'); + if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, 'docs', 'api'))) { + gutil.log('Skipping dartdoc: --fast flag enabled and "docs/api" dir exists'); return true; } checkAngularProjectPath(ngRepoPath); const topLevelLibFilePath = path.resolve(ngRepoPath, 'lib', 'angular2.dart'); const tmpPath = topLevelLibFilePath + '.disabled'; - if (!fs.existsSync(topLevelLibFilePath)) throw new Error(`Missing file: ${topLevelLibFilePath}`); - fs.renameSync(topLevelLibFilePath, tmpPath); + renameIfExistsSync(topLevelLibFilePath, tmpPath); gutil.log(`Hiding top-level angular2 library: ${topLevelLibFilePath}`); - const dartdoc = spawnExt('dartdoc', ['--output', 'doc/api', '--add-crossdart'], { cwd: ngRepoPath}); + const dartdoc = spawnExt('dartdoc', ['--output', 'docs/api', '--add-crossdart'], { cwd: ngRepoPath}); return dartdoc.promise.finally(() => { gutil.log(`Restoring top-level angular2 library: ${topLevelLibFilePath}`); - fs.renameSync(tmpPath, topLevelLibFilePath); + renameIfExistsSync(tmpPath, topLevelLibFilePath); }) }); @@ -1235,15 +1234,14 @@ function buildDartCheatsheet() { function buildApiDocsForDart() { - const apiDir = 'api'; const vers = 'latest'; const dab = require('./tools/dart-api-builder/dab')(ANGULAR_IO_PROJECT_PATH); const log = dab.log; log.level = _dgeniLogLevel; const dabInfo = dab.dartPkgConfigInfo; - dabInfo.ngIoDartApiDocPath = path.join(DOCS_PATH, 'dart', vers, apiDir); - dabInfo.ngDartDocPath = path.join(ngPathFor('dart'), 'doc', apiDir); + dabInfo.ngIoDartApiDocPath = path.join(DOCS_PATH, 'dart', vers, 'api'); + dabInfo.ngDartDocPath = path.join(ngPathFor('dart'), 'docs', 'api'); // Exclude API entries for developer/internal libraries. Also exclude entries for // the top-level catch all "angular2" library (otherwise every entry appears twice). dabInfo.excludeLibRegExp = new RegExp(/^(?!angular2)|\.testing|_|codegen|^angular2$/); @@ -1455,3 +1453,11 @@ function checkAngularProjectPath(_ngPath) { if (fs.existsSync(ngPath)) return; throw new Error('API related tasks require the angular2 repo to be at ' + ngPath); } + +function renameIfExistsSync(oldPath, newPath) { + if (fs.existsSync(oldPath)) { + fs.renameSync(oldPath, newPath); + } else { + gutil.log(`renameIfExistsSync cannot find file to rename: ${oldPath}`); + } +} diff --git a/tools/api-builder/dart-package/test.js b/tools/api-builder/dart-package/test.js index 22ffb7f73d..bba07a62b9 100644 --- a/tools/api-builder/dart-package/test.js +++ b/tools/api-builder/dart-package/test.js @@ -14,7 +14,7 @@ const apiDocPath = path.join(DOCS_PATH, 'dart/latest/api'); dartPkg.config(function (dartPkgConfigInfo) { dartPkgConfigInfo.ngIoDartApiDocPath = apiDocPath; - dartPkgConfigInfo.ngDartDocPath = path.join(ANGULAR_IO_PROJECT_PATH, '../ngdart/doc/api'); + dartPkgConfigInfo.ngDartDocPath = path.join(ANGULAR_IO_PROJECT_PATH, '../angular-dart/docs/api'); }); const dgeni = new Dgeni([dartPkg]); diff --git a/tools/dart-api-builder/dab.js b/tools/dart-api-builder/dab.js index b314719f02..ea1c5b946d 100644 --- a/tools/dart-api-builder/dab.js +++ b/tools/dart-api-builder/dab.js @@ -46,25 +46,53 @@ module.exports = function dabFactory(ngIoProjPath) { log.info(containerName, 'wrote', Object.keys(dataMap).length, 'entries to', dataFilePath); } + function _adjustDocsRelativeLinks($, div) { + // Omit leading https://angular.io so links work for local test sites. + const urlToDocs = '/docs/dart/latest/'; + const urlToExamples = 'http://angular-examples.github.io/'; + const docsLinkList = div.find('a[href^="docs/"],a[href^="examples/"]'); + docsLinkList.each((i, elt) => { + const href = $(elt).attr('href'); + const matches = href.match(/(\w+)\/(.*)$/); + // TODO: support links to chapters of other languages, e.g., 'docs/ts/latest/...'. + const urlStart = matches[1] === 'docs' ? urlToDocs : urlToExamples; + const absHref = urlStart + matches[2]; + log.info(`Found angular.io relative link: ${href} --> ${absHref}`); + $(elt).attr('href', absHref); + }); + } + function _insertExampleFragments(enclosedByName, eltId, $, div) { - const fragDir = path.join(dartPkgConfigInfo.ngIoDartApiDocPath, '../../../_fragments/_api'); + const fragDirBase = path.join(dartPkgConfigInfo.ngIoDartApiDocPath, '../../../_fragments/'); const exList = div.find('p:contains("{@example")'); exList.each((i, elt) => { const text = $(elt).text(); log.debug(`Found example: ${enclosedByName} ${eltId}`, text); - const matches = text.match(/{@example\s+([^\s]+)(\s+region=[\'\"]?(\w+)[\'\"]?)?\s*}/); + const matches = text.match(/^\s*{@example\s+([^\s]+)(\s+region=[\'\"]?([-\w]+)[\'\"]?)?\s*}([\s\S]*)$/); if (!matches) { log.warn(enclosedByName, eltId, 'has an invalidly formed @example tag:', text); return true; } + // const [, exRelPath, /*regionTagAndValue*/, region, rest] = matches; + const rest = matches[4].trim(); + if (rest) log.warn(enclosedByName, eltId, '@example must be the only element in a paragraph, but found:', text); const exRelPath = matches[1]; const region = matches[3]; - const dir = path.dirname(exRelPath) + let exRelPathParts = path.dirname(exRelPath).split(path.sep); + let fragDir; + if (exRelPathParts[0] === 'docs') { + // Path is to a docs example, not an API example. + const exampleName = exRelPathParts[1]; + fragDir = path.join(fragDirBase, exampleName, 'dart'); + exRelPathParts = exRelPathParts.slice(2); + } else { + fragDir = path.join(fragDirBase, '_api'); + } const extn = path.extname(exRelPath); const baseName = path.basename(exRelPath, extn); const fileNameNoExt = baseName + (region ? `-${region}` : '') - const exFragPath = path.resolve(fragDir, dir, `${fileNameNoExt}${extn}.md`); + const exFragPath = path.resolve(fragDir, ...exRelPathParts, `${fileNameNoExt}${extn}.md`); if (!fs.existsSync(exFragPath)) { log.warn('Fragment not found:', exFragPath); return true; @@ -80,7 +108,8 @@ module.exports = function dabFactory(ngIoProjPath) { function _extractAndWrapInCodeTags(md) { const lines = md.split('\n'); // Drop first and last lines that are the code markdown tripple ticks (and last \n): - lines.shift(); lines.pop(); lines.pop(); + lines.shift(); + while (lines && lines.pop().trim() !== '```') {} const code = lines.map((line) => encoder.htmlEncode(line)).join('\n'); // TS uses format="linenums"; removing that for now. return `${code}\n`; @@ -98,6 +127,7 @@ module.exports = function dabFactory(ngIoProjPath) { const div = $('div.body.container'); $('div.sidebar-offcanvas-left').remove(); const baseNameNoExtn = path.basename(e.path, '.html'); + _adjustDocsRelativeLinks($, div); _insertExampleFragments(e.enclosedByQualifiedName, baseNameNoExtn, $, div); const outFileNoExtn = path.join(destDirPath, baseNameNoExtn); From 19d06061c579bcf7832a019cd66a41ce9680187a Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Wed, 10 Aug 2016 13:32:07 -0700 Subject: [PATCH 003/247] docs(quickstart): post-RC5 Dart resync (#2078) * docs(quickstart): post-RC5 Dart resync - Resync Dart QS prose with TS, post RC5. - Added to-be-shared Jade `var` definitions to `_util-fns.jade`. - Delete cached QS jade file. - Eliminate the stub file `styles.1.css` in favor of a `docregion` in the main `styles.css`. This commit requires a `gulp add-example-boilerplate` after pulling it in. Contributes to #2077. * post-review edits --- public/_includes/_util-fns.jade | 9 + .../quickstart/dart/web/styles_1.css | 14 - .../docs/_examples/quickstart/ts/styles.1.css | 14 - public/docs/_examples/styles.css | 2 + public/docs/dart/latest/_util-fns.jade | 9 + public/docs/dart/latest/quickstart.jade | 35 +- public/docs/ts/_cache/quickstart.jade | 582 ------------------ public/docs/ts/latest/quickstart.jade | 150 +++-- 8 files changed, 118 insertions(+), 697 deletions(-) delete mode 100644 public/docs/_examples/quickstart/dart/web/styles_1.css delete mode 100644 public/docs/_examples/quickstart/ts/styles.1.css delete mode 100644 public/docs/ts/_cache/quickstart.jade diff --git a/public/_includes/_util-fns.jade b/public/_includes/_util-fns.jade index 152fbe4bfd..c36f405145 100644 --- a/public/_includes/_util-fns.jade +++ b/public/_includes/_util-fns.jade @@ -38,6 +38,15 @@ //- Location of sample code - var _liveLink = 'live link'; +//- NgModule related +- var _AppModuleVsAppComp = 'AppModule' +- var _appModuleTsVsAppCompTs = 'app/app.module.ts' +- var _appModuleTsVsMainTs = 'app/app.module.ts' +- var _bootstrapModule = 'bootstrapModule' +- var _moduleVsComp = 'module' +- var _moduleVsRootComp = 'module' +- var _platformBrowserDynamicVsBootStrap = 'platformBrowserDynamic' + //- Other - var _truthy = 'truthy'; - var _falsey = 'falsey'; diff --git a/public/docs/_examples/quickstart/dart/web/styles_1.css b/public/docs/_examples/quickstart/dart/web/styles_1.css deleted file mode 100644 index 27e60d67c0..0000000000 --- a/public/docs/_examples/quickstart/dart/web/styles_1.css +++ /dev/null @@ -1,14 +0,0 @@ -/* #docregion */ -h1 { - color: #369; - font-family: Arial, Helvetica, sans-serif; - font-size: 250%; -} -body { - margin: 2em; -} - -/* -* See https://github.com/angular/angular.io/blob/master/public/docs/_examples/styles.css -* for the full set of master styles used by the documentation samples -*/ diff --git a/public/docs/_examples/quickstart/ts/styles.1.css b/public/docs/_examples/quickstart/ts/styles.1.css deleted file mode 100644 index fbc30e2c9e..0000000000 --- a/public/docs/_examples/quickstart/ts/styles.1.css +++ /dev/null @@ -1,14 +0,0 @@ -/* #docregion */ -h1 { - color: #369; - font-family: Arial, Helvetica, sans-serif; - font-size: 250%; -} -body { - margin: 2em; -} - - /* - * See https://github.com/angular/angular.io/blob/master/public/docs/_examples/styles.css - * for the full set of master styles used by the documentation samples - */ diff --git a/public/docs/_examples/styles.css b/public/docs/_examples/styles.css index 62ddfa5121..002017d4bd 100644 --- a/public/docs/_examples/styles.css +++ b/public/docs/_examples/styles.css @@ -1,3 +1,4 @@ +/* #docregion , quickstart */ /* Master Styles */ h1 { color: #369; @@ -12,6 +13,7 @@ h2, h3 { body { margin: 2em; } +/* #enddocregion quickstart */ body, input[text], button { color: #888; font-family: Cambria, Georgia; diff --git a/public/docs/dart/latest/_util-fns.jade b/public/docs/dart/latest/_util-fns.jade index cc59d49fb5..e4839cc688 100644 --- a/public/docs/dart/latest/_util-fns.jade +++ b/public/docs/dart/latest/_util-fns.jade @@ -20,6 +20,15 @@ include ../../../_includes/_util-fns - var _indexHtmlDir = 'web'; - var _mainDir = 'web'; +//- NgModule related +- var _AppModuleVsAppComp = 'AppComponent' +- var _appModuleTsVsAppCompTs = 'app/app_component.dart' +- var _appModuleTsVsMainTs = 'web/main.dart' +- var _bootstrapModule = 'bootstrap' +- var _moduleVsComp = 'component' +- var _moduleVsRootComp = 'root component' +- var _platformBrowserDynamicVsBootStrap = 'bootstrap' + //- Deprecated mixin liveExampleLink(linkText, exampleUrlPartName) - var text = linkText || 'live example'; diff --git a/public/docs/dart/latest/quickstart.jade b/public/docs/dart/latest/quickstart.jade index 8126efc8dc..0150a9a70d 100644 --- a/public/docs/dart/latest/quickstart.jade +++ b/public/docs/dart/latest/quickstart.jade @@ -1,11 +1,13 @@ -extends ../../ts/_cache/quickstart.jade +extends ../../ts/latest/quickstart.jade block includes include _util-fns - var _Install = 'Get' - var _prereq = 'the Dart SDK' - - var _angular_browser_uri = 'package:angular2/platform/browser.dart' - - var _angular_core_uri = 'package:angular2/core.dart' + - 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 @@ -20,9 +22,6 @@ block setup-tooling [DT]: https://www.dartlang.org/tools/ [pub]: https://www.dartlang.org/tools/pub/ -block download-source - // exclude this section from Dart - block package-and-config-files :marked In the project folder just created, create a file named @@ -59,9 +58,6 @@ block create-main li a #[b folder named #[code web]] li a file named #[code #[+adjExPath('app/main.ts')]] with the following content: -block index-html-commentary-for-ts - //- N/A - block run-app p. We have a few options for running our app. @@ -87,10 +83,10 @@ block build-app in the [proper folders](#wrap-up), and run `pub get`. - .l-verbose-section - h3#section-angular-run-app Building the app (generating JavaScript) - + .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. @@ -98,11 +94,12 @@ block build-app > pub build Loading source assets... - p. + :marked The generated JavaScript appears, along with supporting files, - under a directory named build. + under a directory named `build`. - h4#angular_transformer Using the Angular transformer + #angular_transformer + h4 Using the Angular transformer p. When generating JavaScript for an Angular app, @@ -124,7 +121,7 @@ block build-app Angular transformer wiki page. - #performance.l-sub-section + .l-sub-section#performance h3 Performance, the transformer, and Angular 2 libraries p. When an app imports bootstrap.dart, @@ -136,7 +133,8 @@ block build-app (entry_points in pubspec.yaml) so that they don't use mirrors. - h4#dart_to_js_script_rewriter Using dart_to_js_script_rewriter + #dart_to_js_script_rewriter + h4 Using dart_to_js_script_rewriter :marked To improve the app's performance, convert the @@ -203,6 +201,3 @@ block project-files index.html, pubspec.yaml, styles.css`) - -block what-next-ts-overhead - //- N/A diff --git a/public/docs/ts/_cache/quickstart.jade b/public/docs/ts/_cache/quickstart.jade deleted file mode 100644 index 5de3efe99c..0000000000 --- a/public/docs/ts/_cache/quickstart.jade +++ /dev/null @@ -1,582 +0,0 @@ -block includes - include _util-fns - - var _Install = 'Install' - - var _prereq = 'Node.js' - - var _angular_browser_uri = '@angular/platform-browser-dynamic' - - var _angular_core_uri = '@angular/core' - -:marked - Our QuickStart goal is to build and run a super-simple - Angular 2 application in #{_Lang}, and - establish a development environment for the remaining documentation samples - that also can be the foundation for real world applications. - -.callout.is-helpful - header Don't want #{_Lang}? - p. - Although we're getting started in #{_Lang}, you can also write Angular 2 apps - in #{_docsFor == 'ts' ? 'Dart' : 'TypeScript'} and JavaScript. - Just select either of those languages from the combo-box in the banner. - -:marked - # Try it! - - Try the which loads the sample app - - in plunker - - and displays the simple message: - -figure.image-display - img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of QuickStart app") - -:marked - # Build this app! - - - [Prerequisite](#prereq): Install #{_prereq} - - [Step 1](#create-and-configure): Create the app’s project folder and - define package dependencies and special project setup - - [Step 2](#root-component): Create the app’s Angular root component - - [Step 3](#main): Add main.ts, identifying the root component to Angular - - [Step 4](#index): Add `index.html`, the web page that hosts the application - - [Step 5](#build-and-run): Build and run the app - - [Make some changes to the app](#make-some-changes) - - [Wrap up](#wrap-up) - -.l-main-section -h2#prereq Prerequisite: #{_prereq} - -block setup-tooling - :marked - Install **[Node.js® and npm](https://nodejs.org/en/download/)** - if they are not already on your machine. - .l-sub-section - :marked - **Verify that you are running at least node `v4.x.x` and npm `3.x.x`** - by running `node -v` and `npm -v` in a terminal/console window. - Older versions produce errors. - -block download-source - .l-main-section - .callout.is-helpful - header Download the source - :marked - Instead of following each step of these instructions, we can - [download the QuickStart source](https://github.com/angular/quickstart/blob/master/README.md) - from github and follow its brief instructions. - -.l-main-section -button(class="verbose off md-primary md-button md-ink-ripple", type="button", onclick="verbose(false)"). - Hide explanations -button(class="verbose on md-primary md-button md-ink-ripple", type="button", onclick="verbose(true)"). - View explanations -.l-verbose-section - :marked - *Explanations* describe the concepts and reasons behind the instructions. - Explanations have a thin border on the left like *this* block of text. - - Click *Hide Explanations* to show only the instructions. - Click *View Explanations* to see everything again. - -.l-sub-section - :marked - We'll see many code blocks as we build the QuickStart app. They're all easy to copy and paste: - code-example(format="nocode"). - Click the glyph on the right to copy code snippets to the clipboard ==> - -.l-main-section -h2#create-and-configure Step 1: Create and configure the project - -- var _package_and_config_files = _docsFor == 'dart' ? 'pubspec.yaml' : 'package definition and configuration files' - -:marked - In this step we: - * [(a) Create the project folder](#create-the-project-folder) - * [(b) Add #{_package_and_config_files}](#add-config-files) - * [(c) #{_Install} packages](#install-packages) - -h3 (a) Create the project folder - -- var _ = _docsFor == 'dart' ? '_' : '-'; -code-example(language="sh"). - mkdir angular2!{_}quickstart - cd angular2!{_}quickstart - -h3#add-config-files (b) Add #{_package_and_config_files} -block package-and-config-files - - var _tsconfigUri = 'guide/typescript-configuration.html#tsconfig' - - var _typingsUri = 'guide/typescript-configuration.html#!#typings' - - p Add the following package definition and configuration files to the project folder: - ul - li. - #[b package.json] lists packages the QuickStart app depends on and - defines some useful scripts. - See #[a(href="guide/npm-packages.html") Npm Package Configuration] for details. - li. - #[b tsconfig.json] is the TypeScript compiler configuration file. - See #[a(href="#{_tsconfigUri}") TypeScript Configuration] for details. - li. - #[b typings.json] identifies TypeScript definition files. - See #[a(href="#{_typingsUri}") TypeScript Configuration] for details. - li. - #[b systemjs.config.js], the SystemJS configuration file. - See discussion #[a(href="#systemjs") below]. - - a#config-files - +makeTabs(` - quickstart/ts/package.1.json, - quickstart/ts/tsconfig.1.json, - quickstart/ts/typings.1.json, - quickstart/ts/systemjs.config.1.js - `, '', ` - package.json, - tsconfig.json, - typings.json, - systemjs.config.js - `) - -h3#install-packages (c) #{_Install} packages -block install-packages - :marked - We install the packages listed in `package.json` using `npm`. Enter the - following command in a terminal window (command window in Windows): - - code-example(language="sh"). - npm install - - .l-sub-section - :marked - The `typings` folder could not show up after `npm install`. If so, please install them manually. - - code-example(language="sh"). - npm run typings install - - .alert.is-important - :marked - Scary error messages in red may appear **during** install. - The install typically recovers from these errors and finishes successfully. - .l-verbose-section(class="l-verbose-inherit") - :marked - #### npm errors and warnings - - All is well if there are no console messages starting with `npm ERR!` *at the end* of **npm install**. - There might be a few `npm WARN` messages along the way — and that is perfectly fine. - - We often see an `npm WARN` message after a series of `gyp ERR!` messages. - Ignore them. A package may try to recompile itself using `node-gyp`. - If the recompile fails, the package recovers (typically with a pre-built version) - and everything works. - - Just make sure there are no `npm ERR!` messages at the end of `npm install`. - - .l-verbose-section - :marked - #### Adding the libraries and packages we need with *npm* - Angular application developers rely on the _[npm](https://docs.npmjs.com)_ - package manager to install the libraries and packages their apps require. - The Angular team recommends the starter-set of packages specified in the - `dependencies` and `devDependencies` sections. - See the [npm packages](guide/npm-packages.html) chapter for details. - - #### Helpful scripts - We've included a number of npm scripts in our suggested `package.json` to handle common development tasks: - +makeJson('quickstart/ts/package.1.json',{ paths: 'scripts'}, 'package.json (scripts)')(format=".") - - :marked - We execute most npm scripts in the following way: `npm run` followed by a *script-name*. - Some commands (such as `start`) don't require the `run` keyword. - - Here's what these scripts do: - - * `npm start` - runs the compiler and a server at the same time, both in "watch mode" - - * `npm run tsc` - runs the TypeScript compiler once - - * `npm run tsc:w` - runs the TypeScript compiler in watch mode; - the process keeps running, awaiting changes to TypeScript files and recompiling when it sees them - - * `npm run lite` - runs the lite-server, - a light-weight, static file server with excellent support for Angular apps that use routing - - * `npm run typings` - runs the [*typings* tool](#{_typingsUri}) separately - - * `npm run postinstall` - called by *npm* automatically *after* it successfully completes package installation. - This script installs the [TypeScript definition files](#{_typingsUri}) defined in `typings.json` - -:marked - **We're all set.** Let's write some code. - -.l-main-section -h2#root-component Step 2: Our first Angular component -:marked - Let's create a folder to hold our application and add a super-simple Angular component. - - **Create #{_an} #{_appDir} subfolder** off the project root directory: - -code-example. - mkdir #{_appDir} - -a#app-component -p. - #[b Create the component file] - #[code #[+adjExPath('app/app.component.ts')]] (in this newly created directory) with the following content: - -+makeExample('app/app.component.ts') - -.l-verbose-section - :marked - ### AppComponent is the root of the application - - Every Angular app has at least one **root component**, conventionally named `AppComponent`, - that hosts the client user experience. - Components are the basic building blocks of Angular applications. - A component controls a portion of the screen — a *view* — through its associated template. - - This QuickStart has only one, extremely simple component. - But it has the essential structure of every component we'll ever write: - - * One or more [import](#component-import) - statements to reference the things we need. - * A [@Component #{_decorator}](#component-decorator) - that tells Angular what template to use and how to create the component. - * A [component class](#component-class) - that controls the appearance and behavior of a view through its template. - - a#component-import - :marked - ### Import - - Angular apps are modular. They consist of many files each dedicated to a purpose. - Angular itself is modular. It is a collection of library modules - each made up of several, related features that we'll use to build our application. - - When we need something from a module or library, we import it. - Here we import the Angular 2 core so that our component code can have access to - the `@Component` #{_decorator}. - - +makeExcerpt('app/app.component.ts', 'import') - - h3#component-decorator @Component #{_decorator} - +ifDocsFor('ts') - :marked - `Component` is a *decorator function* that takes a *metadata object* as argument. - We apply this function to the component class by prefixing the function with the - **@** symbol and invoking it with a metadata object, just above the class. - :marked - `@Component` is #{_a} *#{_decorator}* that allows us to associate *metadata* with the - component class. - The metadata tells Angular how to create and use this component. - - +makeExcerpt('app/app.component.ts', 'metadata') - - block annotation-fields - :marked - This particular metadata object has two fields, a `selector` and a `template`. - :marked - The **selector** specifies a simple CSS selector for an HTML element that represents the component. - - >The element for this component is named `my-app`. - Angular creates and displays an instance of our `AppComponent` - wherever it encounters a `my-app` element in the host HTML. - - The **template** specifies the component's companion template, - written in an enhanced form of HTML that tells Angular how to render this component's view. - - >Our template is a single line of HTML announcing "*My First Angular 2 App*". - - >A more advanced template could contain data bindings to component properties - and might identify other application components which have their own templates. - These templates might identify yet other components. - In this way an Angular application becomes a tree of components. - - :marked - ### Component class - At the bottom of the file is an empty, do-nothing class named `AppComponent`. - +makeExcerpt('app/app.component.ts', 'class') - :marked - When we're ready to build a substantive application, - we can expand this class with properties and application logic. - Our `AppComponent` class is empty because we don't need it to do anything in this QuickStart. - +ifDocsFor('ts') - :marked - We **export** `AppComponent` so that we can **import** it elsewhere in our application, - as we'll see when we create `main.ts`. - -.l-main-section -h2#main Step 3: Add #[code #[+adjExPath('main.ts')]] - -block create-main - p. - Now we need something to tell Angular to load the root component. - Create the file #[code #[+adjExPath('app/main.ts')]] with the following content: - -+makeExample('app/main.ts') - -.l-verbose-section - :marked - We import the two things we need to launch the application: - - 1. Angular's browser `bootstrap` function - 1. The application root component, `AppComponent`. - - Then we call `bootstrap` with `AppComponent`. - - ### Bootstrapping is platform-specific - Notice that we import the `bootstrap` function from `#{_angular_browser_uri}`, - not `#{_angular_core_uri}`. - Bootstrapping isn't core because there isn't a single way to bootstrap the app. - True, most applications that run in a browser call the bootstrap function from - this library. - - But it is possible to load a component in a different environment. - We might load it on a mobile device with [Apache Cordova](https://cordova.apache.org/) or [NativeScript](https://www.nativescript.org/). - We might wish to render the first page of our application on the server - to improve launch performance or facilitate - [SEO](http://www.google.com/webmasters/docs/search-engine-optimization-starter-guide.pdf). - These targets require a different kind of bootstrap function that we'd import from a different library. - - ### Why create separate *main.ts* and app component files? - - Both main.ts and the app component files are tiny. - This is just a QuickStart. - We could have merged these two files into one - and spared ourselves some complexity. - - We'd rather demonstrate the proper way to structure an Angular application. - App bootstrapping is a separate concern from presenting a view. - Mixing concerns creates difficulties down the road. - We might launch the `AppComponent` in multiple environments with different bootstrappers. - Testing the component is much easier if it doesn't also try to run the entire application. - Let's make the small extra effort to do it *the right way*. - -.l-main-section -h2#index Step 4: Add #[code index.html] -:marked - In the *#{_indexHtmlDir}* folder - create an `index.html` file and paste the following lines into it: - -+makeExample('index.html') - -.l-verbose-section - :marked - The `index.html` file defines the web page that hosts the application. - - block index-html-commentary-for-ts - :marked - The noteworthy sections of HTML are: - - 1. The JavaScript [libraries](#libraries) - 2. Configuration file for [SystemJS](#systemjs), and a script - where we import and run the `app` module which refers to the `main` file that we just wrote. - 3. The [``](#my-app) tag in the `` which is *where our app lives!* - - :marked - ### Libraries - We loaded the following scripts - +makeExcerpt('index.html', 'libraries') - :marked - We begin with `core-js`'s ES2015/ES6 shim which monkey patches the global context (window) with essential features of ES2015 (ES6). - Next are the polyfills for Angular2, `zone.js` and `reflect-metadata`. - Then the [SystemJS](#systemjs) library for module loading. - - We'll make different choices as we gain experience and - become more concerned about production qualities such as - load times and memory footprint. - - h3#systemjs SystemJS - :marked - QuickStart uses SystemJS - to load application and library modules. [Earlier](#add-config-files) we - added the `systemjs.config.js` file to the project root. - There are alternatives that work just fine including the well-regarded - [webpack](guide/webpack.html). - SystemJS happens to be a good choice. - But we want to be clear that it was a *choice* and not a *preference*. - - All module loaders require configuration and all loader configuration - becomes complicated rather quickly as soon as the file structure diversifies and - we start thinking about building for production and performance. - - We suggest becoming well-versed in the loader of your choice. - Learn more about SystemJS configuration - here. - - With those cautions in mind, what are we doing in the - QuickStart [`systemjs.config.js` configuration file we added earlier](#config-files)? - First, we create a map to tell SystemJS where to look when we import some module. - Then, we register all our packages to SystemJS: - all the project dependencies and our application package, `app`. - - .l-sub-section - :marked - Our QuickStart doesn't use all of the listed packages - but any substantial application will want many of them - and all of the listed packages are required by at least one of the documentation samples. - - There is no runtime harm in listing packages that we don't need as they will only be loaded when requested. - :marked - The `app` package tells SystemJS what to do when it sees a request for a - module from the `app/` folder. - - Our QuickStart makes such requests when one of its - application TypeScript files has an import statement like this: - +makeExcerpt('app/main.ts', 'import') - :marked - Notice that the module name (after `from`) does not mention a filename extension. - In the configuration we tell SystemJS to default the extension to `js`, a JavaScript file. - - That makes sense because we transpile TypeScript to JavaScript - *before* running the application. - - .l-sub-section - :marked - #### Transpiling in the browser - In the live example on plunker we transpile (AKA compile) to JavaScript in the browser - on the fly. _That's fine for a demo_. - - **Do not transpile in the browser during development or for production**. - - We strongly recommend transpiling (AKA compiling) to JavaScript during a build phase - before running the application for several reasons including: - - * We see compiler warnings and errors that are hidden from us in the browser. - - * Precompilation simplifies the module loading process and - it's much easier to diagnose problems when this is a separate, external step. - - * Precompilation means a faster user experience because the browser doesn't waste time compiling. - - * We iterate development faster because we only recompile changed files. - We notice the difference as soon as the app grows beyond a handful of files. - - * Precompilation fits into a continuous integration process of build, test, deploy. - - :marked - The `System.import` call tells SystemJS to import the `main` file - (`main.js` ... after transpiling `main.ts`, remember?); - `main` is where we tell Angular to launch the application. - We also catch and log launch errors to the console. - - All other modules are loaded upon request - either by an import statement or by Angular itself. - - ### *<my-app>* - - a(id="my-app") - :marked - When Angular calls the `bootstrap` function in main.ts, it reads the `AppComponent` - metadata, finds the `my-app` selector, locates an element tag named `my-app`, - and renders our application's view between those tags. - -:marked - ### Add some style - Styles aren't essential but they're nice, and `index.html` assumes we have - a stylesheet called `styles.css`. - - Create a `styles.css` file in the *#{_indexHtmlDir}* folder and start styling, perhaps with the minimal - styles shown below. For the full set of master styles used by the documentation samples, - see [styles.css](https://github.com/angular/angular.io/blob/master/public/docs/_examples/styles.css). -+makeExcerpt('styles.1.css') - -.l-main-section -h2#build-and-run Step 5: Build and run the app! -block run-app - :marked - Open a terminal window and enter this command: - code-example. - npm start - :marked - That command runs two parallel node processes - 1. The TypeScript compiler in watch mode - 1. A static server called **lite-server** that loads `index.html` in a browser - and refreshes the browser when application files change - - In a few moments, a browser tab should open and display - -figure.image-display - img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of QuickStart app") - -:marked - **Great job!** - -block build-app - //- Nothing for ts. - -:marked - ## Make some changes - - Try changing the message to "My SECOND Angular 2 app". -block server-watching - :marked - The TypeScript compiler and `lite-server` are watching. - They should detect the change, recompile the TypeScript into JavaScript, - refresh the browser, and display the revised message. - It's a nifty way to develop an application! - - We close the terminal window when we're done to terminate both the compiler and the server. - -.l-main-section -:marked - # Wrap up - - Our final project folder structure looks like this: -block project-file-structure - .filetree - .file angular2-quickstart - .children - .file app - .children - .file app.component.ts - .file main.ts - .file node_modules ... - .file typings ... - .file index.html - .file package.json - .file styles.css - .file systemjs.config.js - .file tsconfig.json - .file typings.json -:marked - Here are the file contents: - -block project-files - +makeTabs(` - quickstart/ts/app/app.component.ts, - quickstart/ts/app/main.ts, - quickstart/ts/index.html, - quickstart/ts/package.1.json, - quickstart/ts/tsconfig.1.json, - quickstart/ts/typings.1.json, - quickstart/ts/styles.1.css, - quickstart/ts/systemjs.config.1.js` - ,null, - `app/app.component.ts, - app/main.ts, - index.html, - package.json, - tsconfig.json, - typings.json, - styles.css, - systemjs.config.js`) - -.l-main-section -:marked - ## What next? - Our first application doesn't do much. It's basically "Hello, World" for Angular 2. - - We kept it simple in our first pass: we wrote a little Angular component, - created a simple `index.html`, and launched with a - static file server. That's about all we'd expect to do for a "Hello, World" app. - - **We have greater ambitions!** -block what-next-ts-overhead - :marked - The good news is that the overhead of setup is (mostly) behind us. - We'll probably only touch the `package.json` to update libraries. - We'll likely open `index.html` only if we need to add a library or some css stylesheets. -:marked - We're about to take the next step and build a small application that - demonstrates the great things we can build with Angular 2. - - Join us on the [Tour of Heroes Tutorial](./tutorial)! diff --git a/public/docs/ts/latest/quickstart.jade b/public/docs/ts/latest/quickstart.jade index 5cdbb93200..79a258946b 100644 --- a/public/docs/ts/latest/quickstart.jade +++ b/public/docs/ts/latest/quickstart.jade @@ -4,6 +4,11 @@ block includes - var _prereq = 'Node.js' - var _angular_browser_uri = '@angular/platform-browser-dynamic' - var _angular_core_uri = '@angular/core' + - var _stepInit = 4 // Step # after NgModule step + - var _quickstartSrcURL='https://github.com/angular/quickstart/blob/master/README.md' + +//- TS/Dart shared step counter +- var step = _stepInit :marked Our QuickStart goal is to build and run a super-simple @@ -37,15 +42,16 @@ figure.image-display - [Step 1](#create-and-configure): Create the app’s project folder and define package dependencies and special project setup - [Step 2](#root-component): Create the app’s Angular root component - - [Step 3](#ngmodule): Create an Angular Module - - [Step 4](#main): Add main.ts, identifying the root component to Angular - - [Step 5](#index): Add `index.html`, the web page that hosts the application - - [Step 6](#build-and-run): Build and run the app +
  • [Step 3](#ngmodule): Create an Angular Module
  • + - [Step !{step++}](#main): Add main.ts, identifying the root component to Angular + - [Step !{step++}](#index): Add `index.html`, the web page that hosts the application + - [Step !{step++}](#build-and-run): Build and run the app - [Make some changes to the app](#make-some-changes) - [Wrap up](#wrap-up) -.l-main-section -h2#prereq Prerequisite: #{_prereq} +- var step = _stepInit // reinitialize step counter for headers to come +.l-main-section#prereq +h2 Prerequisite: #{_prereq} block setup-tooling :marked @@ -57,14 +63,13 @@ block setup-tooling by running `node -v` and `npm -v` in a terminal/console window. Older versions produce errors. -block download-source - .l-main-section - .callout.is-helpful - header Download the source - :marked - Instead of following each step of these instructions, we can - [download the QuickStart source](https://github.com/angular/quickstart/blob/master/README.md) - from github and follow its brief instructions. +.l-main-section +.callout.is-helpful + header Download the source + :marked + Instead of following each step of these instructions, we can + [download the QuickStart source](!{_quickstartSrcURL}) + from GitHub and follow its brief instructions. .l-main-section button(class="verbose off md-primary md-button md-ink-ripple", type="button", onclick="verbose(false)"). @@ -85,18 +90,18 @@ button(class="verbose on md-primary md-button md-ink-ripple", type="button", onc code-example(format="nocode"). Click the glyph on the right to copy code snippets to the clipboard ==> -.l-main-section -h2#create-and-configure Step 1: Create and configure the project - - var _package_and_config_files = _docsFor == 'dart' ? 'pubspec.yaml' : 'package definition and configuration files' +.l-main-section#create-and-configure :marked + ## Step 1: Create and configure the project + In this step we: * [(a) Create the project folder](#create-the-project-folder) * [(b) Add #{_package_and_config_files}](#add-config-files) * [(c) #{_Install} packages](#install-packages) -h3 (a) Create the project folder + ### (a) Create the project folder - var _ = _docsFor == 'dart' ? '_' : '-'; code-example(language="sh"). @@ -208,9 +213,10 @@ block install-packages :marked **We're all set.** Let's write some code. -.l-main-section -h2#root-component Step 2: Our first Angular component +.l-main-section#root-component :marked + ## Step 2: Our first Angular component + Let's create a folder to hold our application and add a super-simple Angular component. **Create #{_an} #{_appDir} subfolder** off the project root directory: @@ -304,87 +310,91 @@ p. We **export** `AppComponent` so that we can **import** it elsewhere in our application, as we'll see when we create `app.module.ts`. -.l-main-section -h2#ngmodule Step 3: Our own #[code #[+adjExPath('app.module.ts')]] - -block create-ngmodule ++ifDocsFor('ts') + .l-main-section#ngmodule :marked + ## Step 3: Our own `app.module.ts` + We compose Angular apps into closely related blocks of functionality with [Angular Modules](guide/ngmodule.html). Every app requires at least one module, the _root module_, that we call `AppModule` by convention. - p. - Create the file #[code #[+adjExPath('app/app.module.ts')]] with the following content: -+makeExample('app/app.module.ts')(format='.') + Create the file `app/app.module.ts` with the following content: -.l-verbose-section - :marked - We're passing metadata to the `NgModule` decorator function: + +makeExample('app/app.module.ts')(format='.') - 1. `imports` - the _other_ modules that export material we need in _this_ module. - Almost every application's _root module_ should import the `BrowserModule`. + .l-verbose-section + :marked + We're passing metadata to the `NgModule` decorator function: - 1. `declarations` - components and directives that belong to _this_ module. + 1. `imports` - the _other_ modules that export material we need in _this_ module. + Almost every application's _root module_ should import the `BrowserModule`. - 1. `bootstrap` - identifies the _root component_ that Angular should _bootstrap_ when it starts the application. + 1. `declarations` - components and directives that belong to _this_ module. - We import our lone `app.component.ts` and add it to both the `declarations` and `bootstrap` arrays. + 1. `bootstrap` - identifies the _root component_ that Angular should _bootstrap_ when it starts the application. - ### Angular Modules import other modules - Notice that we also add the `BrowserModule` from `@angular/platform-browser` to the `imports` array. - This is the Angular Module that contains all the needed Angular bits and pieces to run our app in the browser. + We import our lone `app.component.ts` and add it to both the `declarations` and `bootstrap` arrays. - Angular itself is split into separate Angular Modules so we only need to import the ones we really use. - - One of the most common ones is `FormsModule`, and soon we'll also see `RouterModule` and `HttpModule`. + ### Angular Modules import other modules + Notice that we also add the `BrowserModule` from `@angular/platform-browser` to the `imports` array. + This is the Angular Module that contains all the needed Angular bits and pieces to run our app in the browser. + + Angular itself is split into separate Angular Modules so we only need to import the ones we really use. + + One of the most common ones is `FormsModule`, and soon we'll also see `RouterModule` and `HttpModule`. .l-main-section -h2#main Step 4: Add #[code #[+adjExPath('main.ts')]] +h2#main Step !{step++}: Add #[code #[+adjExPath('main.ts')]] block create-main - p. + :marked Now we need something to tell Angular to load the app module. - Create the file #[code #[+adjExPath('app/main.ts')]] with the following content: + Create the file `app/main.ts` with the following content: +makeExample('app/main.ts') +- var _pBD_bootstrapModule = _docsFor == 'dart' ? _bootstrapModule : 'platformBrowserDynamic().bootstrapModule' .l-verbose-section :marked We import the two things we need to launch the application: - 1. Angular's browser `platformBrowserDynamic` function - 1. The application module, `AppModule`. + 1. Angular's browser `!{_platformBrowserDynamicVsBootStrap}` function + 1. The application !{_moduleVsRootComp}, `!{_AppModuleVsAppComp}`. - Then we call `platformBrowserDynamic().bootstrapModule` with `AppComponent`. + Then we call `!{_pBD_bootstrapModule}` with `AppComponent`. ### Bootstrapping is platform-specific - Notice that we import the `platformBrowserDynamic` function from `#{_angular_browser_uri}`, - not `#{_angular_core_uri}`. + + Notice that we import the `!{_platformBrowserDynamicVsBootStrap}` function + from `#{_angular_browser_uri}`, not `#{_angular_core_uri}`. Bootstrapping isn't core because there isn't a single way to bootstrap the app. True, most applications that run in a browser call the bootstrap function from this library. - But it is possible to load a module in a different environment. + But it is possible to load a !{_moduleVsComp} in a different environment. We might load it on a mobile device with [Apache Cordova](https://cordova.apache.org/) or [NativeScript](https://www.nativescript.org/). We might wish to render the first page of our application on the server to improve launch performance or facilitate [SEO](http://www.google.com/webmasters/docs/search-engine-optimization-starter-guide.pdf). These targets require a different kind of bootstrap function that we'd import from a different library. - ### Why create separate *main.ts*, app module and app component files? + ### Why create separate *main.ts*, app module and app component files? - Both main.ts, app module and the app component files are tiny. + Then main.ts, app module + and the app component files are tiny. This is just a QuickStart. - We could have merged these three files into one and spared ourselves some complexity. + We could have merged these files into one and spared ourselves some complexity. We'd rather demonstrate the proper way to structure an Angular application. - App bootstrapping is a separate concern from creating a module or presenting a view. + App bootstrapping is a separate concern from creating a module or + presenting a view. Mixing concerns creates difficulties down the road. - We might launch the `AppModule` in multiple environments with different bootstrappers. + We might launch the `!{_AppModuleVsAppComp}` in multiple environments with different bootstrappers. Testing the component is much easier if it doesn't also try to run the entire application. Let's make the small extra effort to do it *the right way*. .l-main-section -h2#index Step 5: Add #[code index.html] +h2#index Step !{step++}: Add #[code index.html] :marked In the *#{_indexHtmlDir}* folder create an `index.html` file and paste the following lines into it: @@ -395,7 +405,7 @@ h2#index Step 5: Add #[code index.html] :marked The `index.html` file defines the web page that hosts the application. - block index-html-commentary-for-ts + +ifDocsFor('ts') :marked The noteworthy sections of HTML are: @@ -496,10 +506,11 @@ h2#index Step 5: Add #[code index.html] ### *<my-app>* - a(id="my-app") + a#my-app :marked - When Angular calls the `bootstrapModule` function in main.ts, - it reads the `AppModule` metadata, sees that `AppComponent` is the bootstrap component, + When Angular calls the `!{_bootstrapModule}` function in main.ts, + it reads the `!{_AppModuleVsAppComp}` metadata, sees that + `AppComponent` is the bootstrap component, finds the `my-app` selector, locates an element tag named `my-app`, and renders our application's view between those tags. @@ -508,13 +519,18 @@ h2#index Step 5: Add #[code index.html] Styles aren't essential but they're nice, and `index.html` assumes we have a stylesheet called `styles.css`. - Create a `styles.css` file in the *#{_indexHtmlDir}* folder and start styling, perhaps with the minimal - styles shown below. For the full set of master styles used by the documentation samples, - see [styles.css](https://github.com/angular/angular.io/blob/master/public/docs/_examples/styles.css). -+makeExcerpt('styles.1.css') + Create a `styles.css` file in the *#{_indexHtmlDir}* folder and start styling, + perhaps with the minimal styles shown below. -.l-main-section -h2#build-and-run Step 6: Build and run the app! ++makeExcerpt('styles.css (excerpt)', 'quickstart') + +.callout.is-helpful + :marked + For the full set of master styles used by the documentation samples, + see [styles.css](https://github.com/angular/angular.io/blob/master/public/docs/_examples/styles.css). + +.l-main-section#build-and-run +h2 Step !{step++}: Build and run the app! block run-app :marked Open a terminal window and enter this command: @@ -608,7 +624,7 @@ block project-files static file server. That's about all we'd expect to do for a "Hello, World" app. **We have greater ambitions!** -block what-next-ts-overhead ++ifDocsFor('ts') :marked The good news is that the overhead of setup is (mostly) behind us. We'll probably only touch the `package.json` to update libraries. From 2ca6d6567b907cfb8ac0aef67de1107e18a450a8 Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Thu, 11 Aug 2016 11:29:19 -0700 Subject: [PATCH 004/247] chore(quickstart/dart): refresh ts _cache (#2089) Cf. #2088 and #2077. --- public/docs/dart/latest/quickstart.jade | 2 +- public/docs/ts/_cache/quickstart.jade | 636 ++++++++++++++++++++++++ 2 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 public/docs/ts/_cache/quickstart.jade diff --git a/public/docs/dart/latest/quickstart.jade b/public/docs/dart/latest/quickstart.jade index 0150a9a70d..84085d64c7 100644 --- a/public/docs/dart/latest/quickstart.jade +++ b/public/docs/dart/latest/quickstart.jade @@ -1,4 +1,4 @@ -extends ../../ts/latest/quickstart.jade +extends ../../ts/_cache/quickstart.jade block includes include _util-fns diff --git a/public/docs/ts/_cache/quickstart.jade b/public/docs/ts/_cache/quickstart.jade new file mode 100644 index 0000000000..79a258946b --- /dev/null +++ b/public/docs/ts/_cache/quickstart.jade @@ -0,0 +1,636 @@ +block includes + include _util-fns + - var _Install = 'Install' + - var _prereq = 'Node.js' + - var _angular_browser_uri = '@angular/platform-browser-dynamic' + - var _angular_core_uri = '@angular/core' + - var _stepInit = 4 // Step # after NgModule step + - var _quickstartSrcURL='https://github.com/angular/quickstart/blob/master/README.md' + +//- TS/Dart shared step counter +- var step = _stepInit + +:marked + Our QuickStart goal is to build and run a super-simple + Angular 2 application in #{_Lang}, and + establish a development environment for the remaining documentation samples + that also can be the foundation for real world applications. + +.callout.is-helpful + header Don't want #{_Lang}? + p. + Although we're getting started in #{_Lang}, you can also write Angular 2 apps + in #{_docsFor == 'ts' ? 'Dart' : 'TypeScript'} and JavaScript. + Just select either of those languages from the combo-box in the banner. + +:marked + # Try it! + + Try the which loads the sample app + + in plunker + + and displays the simple message: + +figure.image-display + img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of QuickStart app") + +:marked + # Build this app! + + - [Prerequisite](#prereq): Install #{_prereq} + - [Step 1](#create-and-configure): Create the app’s project folder and + define package dependencies and special project setup + - [Step 2](#root-component): Create the app’s Angular root component +
  • [Step 3](#ngmodule): Create an Angular Module
  • + - [Step !{step++}](#main): Add main.ts, identifying the root component to Angular + - [Step !{step++}](#index): Add `index.html`, the web page that hosts the application + - [Step !{step++}](#build-and-run): Build and run the app + - [Make some changes to the app](#make-some-changes) + - [Wrap up](#wrap-up) + +- var step = _stepInit // reinitialize step counter for headers to come +.l-main-section#prereq +h2 Prerequisite: #{_prereq} + +block setup-tooling + :marked + Install **[Node.js® and npm](https://nodejs.org/en/download/)** + if they are not already on your machine. + .l-sub-section + :marked + **Verify that you are running at least node `v4.x.x` and npm `3.x.x`** + by running `node -v` and `npm -v` in a terminal/console window. + Older versions produce errors. + +.l-main-section +.callout.is-helpful + header Download the source + :marked + Instead of following each step of these instructions, we can + [download the QuickStart source](!{_quickstartSrcURL}) + from GitHub and follow its brief instructions. + +.l-main-section +button(class="verbose off md-primary md-button md-ink-ripple", type="button", onclick="verbose(false)"). + Hide explanations +button(class="verbose on md-primary md-button md-ink-ripple", type="button", onclick="verbose(true)"). + View explanations +.l-verbose-section + :marked + *Explanations* describe the concepts and reasons behind the instructions. + Explanations have a thin border on the left like *this* block of text. + + Click *Hide Explanations* to show only the instructions. + Click *View Explanations* to see everything again. + +.l-sub-section + :marked + We'll see many code blocks as we build the QuickStart app. They're all easy to copy and paste: + code-example(format="nocode"). + Click the glyph on the right to copy code snippets to the clipboard ==> + +- var _package_and_config_files = _docsFor == 'dart' ? 'pubspec.yaml' : 'package definition and configuration files' + +.l-main-section#create-and-configure +:marked + ## Step 1: Create and configure the project + + In this step we: + * [(a) Create the project folder](#create-the-project-folder) + * [(b) Add #{_package_and_config_files}](#add-config-files) + * [(c) #{_Install} packages](#install-packages) + + ### (a) Create the project folder + +- var _ = _docsFor == 'dart' ? '_' : '-'; +code-example(language="sh"). + mkdir angular2!{_}quickstart + cd angular2!{_}quickstart + +h3#add-config-files (b) Add #{_package_and_config_files} +block package-and-config-files + - var _tsconfigUri = 'guide/typescript-configuration.html#tsconfig' + - var _typingsUri = 'guide/typescript-configuration.html#!#typings' + + p Add the following package definition and configuration files to the project folder: + ul + li. + #[b package.json] lists packages the QuickStart app depends on and + defines some useful scripts. + See #[a(href="guide/npm-packages.html") Npm Package Configuration] for details. + li. + #[b tsconfig.json] is the TypeScript compiler configuration file. + See #[a(href="#{_tsconfigUri}") TypeScript Configuration] for details. + li. + #[b typings.json] identifies TypeScript definition files. + See #[a(href="#{_typingsUri}") TypeScript Configuration] for details. + li. + #[b systemjs.config.js], the SystemJS configuration file. + See discussion #[a(href="#systemjs") below]. + + a#config-files + +makeTabs(` + quickstart/ts/package.1.json, + quickstart/ts/tsconfig.1.json, + quickstart/ts/typings.1.json, + quickstart/ts/systemjs.config.1.js + `, '', ` + package.json, + tsconfig.json, + typings.json, + systemjs.config.js + `) + +h3#install-packages (c) #{_Install} packages +block install-packages + :marked + We install the packages listed in `package.json` using `npm`. Enter the + following command in a terminal window (command window in Windows): + + code-example(language="sh"). + npm install + + .l-sub-section + :marked + The `typings` folder could not show up after `npm install`. If so, please install them manually. + + code-example(language="sh"). + npm run typings install + + .alert.is-important + :marked + Scary error messages in red may appear **during** install. + The install typically recovers from these errors and finishes successfully. + .l-verbose-section(class="l-verbose-inherit") + :marked + #### npm errors and warnings + + All is well if there are no console messages starting with `npm ERR!` *at the end* of **npm install**. + There might be a few `npm WARN` messages along the way — and that is perfectly fine. + + We often see an `npm WARN` message after a series of `gyp ERR!` messages. + Ignore them. A package may try to recompile itself using `node-gyp`. + If the recompile fails, the package recovers (typically with a pre-built version) + and everything works. + + Just make sure there are no `npm ERR!` messages at the end of `npm install`. + + .l-verbose-section + :marked + #### Adding the libraries and packages we need with *npm* + Angular application developers rely on the _[npm](https://docs.npmjs.com)_ + package manager to install the libraries and packages their apps require. + The Angular team recommends the starter-set of packages specified in the + `dependencies` and `devDependencies` sections. + See the [npm packages](guide/npm-packages.html) chapter for details. + + #### Helpful scripts + We've included a number of npm scripts in our suggested `package.json` to handle common development tasks: + +makeJson('quickstart/ts/package.1.json',{ paths: 'scripts'}, 'package.json (scripts)')(format=".") + + :marked + We execute most npm scripts in the following way: `npm run` followed by a *script-name*. + Some commands (such as `start`) don't require the `run` keyword. + + Here's what these scripts do: + + * `npm start` - runs the compiler and a server at the same time, both in "watch mode" + + * `npm run tsc` - runs the TypeScript compiler once + + * `npm run tsc:w` - runs the TypeScript compiler in watch mode; + the process keeps running, awaiting changes to TypeScript files and recompiling when it sees them + + * `npm run lite` - runs the lite-server, + a light-weight, static file server with excellent support for Angular apps that use routing + + * `npm run typings` - runs the [*typings* tool](#{_typingsUri}) separately + + * `npm run postinstall` - called by *npm* automatically *after* it successfully completes package installation. + This script installs the [TypeScript definition files](#{_typingsUri}) defined in `typings.json` + +:marked + **We're all set.** Let's write some code. + +.l-main-section#root-component +:marked + ## Step 2: Our first Angular component + + Let's create a folder to hold our application and add a super-simple Angular component. + + **Create #{_an} #{_appDir} subfolder** off the project root directory: + +code-example. + mkdir #{_appDir} + +a#app-component +p. + #[b Create the component file] + #[code #[+adjExPath('app/app.component.ts')]] (in this newly created directory) with the following content: + ++makeExample('app/app.component.ts') + +.l-verbose-section + :marked + ### AppComponent is the root of the application + + Every Angular app has at least one **root component**, conventionally named `AppComponent`, + that hosts the client user experience. + Components are the basic building blocks of Angular applications. + A component controls a portion of the screen — a *view* — through its associated template. + + This QuickStart has only one, extremely simple component. + But it has the essential structure of every component we'll ever write: + + * One or more [import](#component-import) + statements to reference the things we need. + * A [@Component #{_decorator}](#component-decorator) + that tells Angular what template to use and how to create the component. + * A [component class](#component-class) + that controls the appearance and behavior of a view through its template. + + a#component-import + :marked + ### Import + + Angular apps are modular. They consist of many files each dedicated to a purpose. + Angular itself is modular. It is a collection of library modules + each made up of several, related features that we'll use to build our application. + + When we need something from a module or library, we import it. + Here we import the Angular 2 core so that our component code can have access to + the `@Component` #{_decorator}. + + +makeExcerpt('app/app.component.ts', 'import') + + h3#component-decorator @Component #{_decorator} + +ifDocsFor('ts') + :marked + `Component` is a *decorator function* that takes a *metadata object* as argument. + We apply this function to the component class by prefixing the function with the + **@** symbol and invoking it with a metadata object, just above the class. + :marked + `@Component` is #{_a} *#{_decorator}* that allows us to associate *metadata* with the + component class. + The metadata tells Angular how to create and use this component. + + +makeExcerpt('app/app.component.ts', 'metadata') + + block annotation-fields + :marked + This particular metadata object has two fields, a `selector` and a `template`. + :marked + The **selector** specifies a simple CSS selector for an HTML element that represents the component. + + >The element for this component is named `my-app`. + Angular creates and displays an instance of our `AppComponent` + wherever it encounters a `my-app` element in the host HTML. + + The **template** specifies the component's companion template, + written in an enhanced form of HTML that tells Angular how to render this component's view. + + >Our template is a single line of HTML announcing "*My First Angular 2 App*". + + >A more advanced template could contain data bindings to component properties + and might identify other application components which have their own templates. + These templates might identify yet other components. + In this way an Angular application becomes a tree of components. + + :marked + ### Component class + At the bottom of the file is an empty, do-nothing class named `AppComponent`. + +makeExcerpt('app/app.component.ts', 'class') + :marked + When we're ready to build a substantive application, + we can expand this class with properties and application logic. + Our `AppComponent` class is empty because we don't need it to do anything in this QuickStart. + +ifDocsFor('ts') + :marked + We **export** `AppComponent` so that we can **import** it elsewhere in our application, + as we'll see when we create `app.module.ts`. + ++ifDocsFor('ts') + .l-main-section#ngmodule + :marked + ## Step 3: Our own `app.module.ts` + + We compose Angular apps into closely related blocks of functionality with [Angular Modules](guide/ngmodule.html). + Every app requires at least one module, the _root module_, that we call `AppModule` by convention. + + Create the file `app/app.module.ts` with the following content: + + +makeExample('app/app.module.ts')(format='.') + + .l-verbose-section + :marked + We're passing metadata to the `NgModule` decorator function: + + 1. `imports` - the _other_ modules that export material we need in _this_ module. + Almost every application's _root module_ should import the `BrowserModule`. + + 1. `declarations` - components and directives that belong to _this_ module. + + 1. `bootstrap` - identifies the _root component_ that Angular should _bootstrap_ when it starts the application. + + We import our lone `app.component.ts` and add it to both the `declarations` and `bootstrap` arrays. + + ### Angular Modules import other modules + Notice that we also add the `BrowserModule` from `@angular/platform-browser` to the `imports` array. + This is the Angular Module that contains all the needed Angular bits and pieces to run our app in the browser. + + Angular itself is split into separate Angular Modules so we only need to import the ones we really use. + + One of the most common ones is `FormsModule`, and soon we'll also see `RouterModule` and `HttpModule`. + +.l-main-section +h2#main Step !{step++}: Add #[code #[+adjExPath('main.ts')]] + +block create-main + :marked + Now we need something to tell Angular to load the app module. + Create the file `app/main.ts` with the following content: + ++makeExample('app/main.ts') + +- var _pBD_bootstrapModule = _docsFor == 'dart' ? _bootstrapModule : 'platformBrowserDynamic().bootstrapModule' +.l-verbose-section + :marked + We import the two things we need to launch the application: + + 1. Angular's browser `!{_platformBrowserDynamicVsBootStrap}` function + 1. The application !{_moduleVsRootComp}, `!{_AppModuleVsAppComp}`. + + Then we call `!{_pBD_bootstrapModule}` with `AppComponent`. + + ### Bootstrapping is platform-specific + + Notice that we import the `!{_platformBrowserDynamicVsBootStrap}` function + from `#{_angular_browser_uri}`, not `#{_angular_core_uri}`. + Bootstrapping isn't core because there isn't a single way to bootstrap the app. + True, most applications that run in a browser call the bootstrap function from + this library. + + But it is possible to load a !{_moduleVsComp} in a different environment. + We might load it on a mobile device with [Apache Cordova](https://cordova.apache.org/) or [NativeScript](https://www.nativescript.org/). + We might wish to render the first page of our application on the server + to improve launch performance or facilitate + [SEO](http://www.google.com/webmasters/docs/search-engine-optimization-starter-guide.pdf). + These targets require a different kind of bootstrap function that we'd import from a different library. + + ### Why create separate *main.ts*, app module and app component files? + + Then main.ts, app module + and the app component files are tiny. + This is just a QuickStart. + We could have merged these files into one and spared ourselves some complexity. + + We'd rather demonstrate the proper way to structure an Angular application. + App bootstrapping is a separate concern from creating a module or + presenting a view. + Mixing concerns creates difficulties down the road. + We might launch the `!{_AppModuleVsAppComp}` in multiple environments with different bootstrappers. + Testing the component is much easier if it doesn't also try to run the entire application. + Let's make the small extra effort to do it *the right way*. + +.l-main-section +h2#index Step !{step++}: Add #[code index.html] +:marked + In the *#{_indexHtmlDir}* folder + create an `index.html` file and paste the following lines into it: + ++makeExample('index.html') + +.l-verbose-section + :marked + The `index.html` file defines the web page that hosts the application. + + +ifDocsFor('ts') + :marked + The noteworthy sections of HTML are: + + 1. The JavaScript [libraries](#libraries) + 2. Configuration file for [SystemJS](#systemjs), and a script + where we import and run the `app` module which refers to the `main` file that we just wrote. + 3. The [``](#my-app) tag in the `` which is *where our app lives!* + + :marked + ### Libraries + We loaded the following scripts + +makeExcerpt('index.html', 'libraries') + :marked + We begin with `core-js`'s ES2015/ES6 shim which monkey patches the global context (window) with essential features of ES2015 (ES6). + Next are the polyfills for Angular2, `zone.js` and `reflect-metadata`. + Then the [SystemJS](#systemjs) library for module loading. + + We'll make different choices as we gain experience and + become more concerned about production qualities such as + load times and memory footprint. + + h3#systemjs SystemJS + :marked + QuickStart uses SystemJS + to load application and library modules. [Earlier](#add-config-files) we + added the `systemjs.config.js` file to the project root. + There are alternatives that work just fine including the well-regarded + [webpack](guide/webpack.html). + SystemJS happens to be a good choice. + But we want to be clear that it was a *choice* and not a *preference*. + + All module loaders require configuration and all loader configuration + becomes complicated rather quickly as soon as the file structure diversifies and + we start thinking about building for production and performance. + + We suggest becoming well-versed in the loader of your choice. + Learn more about SystemJS configuration + here. + + With those cautions in mind, what are we doing in the + QuickStart [`systemjs.config.js` configuration file we added earlier](#config-files)? + First, we create a map to tell SystemJS where to look when we import some module. + Then, we register all our packages to SystemJS: + all the project dependencies and our application package, `app`. + + .l-sub-section + :marked + Our QuickStart doesn't use all of the listed packages + but any substantial application will want many of them + and all of the listed packages are required by at least one of the documentation samples. + + There is no runtime harm in listing packages that we don't need as they will only be loaded when requested. + :marked + The `app` package tells SystemJS what to do when it sees a request for a + module from the `app/` folder. + + Our QuickStart makes such requests when one of its + application TypeScript files has an import statement like this: + +makeExcerpt('app/main.ts', 'import') + :marked + Notice that the module name (after `from`) does not mention a filename extension. + In the configuration we tell SystemJS to default the extension to `js`, a JavaScript file. + + That makes sense because we transpile TypeScript to JavaScript + *before* running the application. + + .l-sub-section + :marked + #### Transpiling in the browser + In the live example on plunker we transpile (AKA compile) to JavaScript in the browser + on the fly. _That's fine for a demo_. + + **Do not transpile in the browser during development or for production**. + + We strongly recommend transpiling (AKA compiling) to JavaScript during a build phase + before running the application for several reasons including: + + * We see compiler warnings and errors that are hidden from us in the browser. + + * Precompilation simplifies the module loading process and + it's much easier to diagnose problems when this is a separate, external step. + + * Precompilation means a faster user experience because the browser doesn't waste time compiling. + + * We iterate development faster because we only recompile changed files. + We notice the difference as soon as the app grows beyond a handful of files. + + * Precompilation fits into a continuous integration process of build, test, deploy. + + :marked + The `System.import` call tells SystemJS to import the `main` file + (`main.js` ... after transpiling `main.ts`, remember?); + `main` is where we tell Angular to launch the application. + We also catch and log launch errors to the console. + + All other modules are loaded upon request + either by an import statement or by Angular itself. + + ### *<my-app>* + + a#my-app + :marked + When Angular calls the `!{_bootstrapModule}` function in main.ts, + it reads the `!{_AppModuleVsAppComp}` metadata, sees that + `AppComponent` is the bootstrap component, + finds the `my-app` selector, locates an element tag named `my-app`, + and renders our application's view between those tags. + +:marked + ### Add some style + Styles aren't essential but they're nice, and `index.html` assumes we have + a stylesheet called `styles.css`. + + Create a `styles.css` file in the *#{_indexHtmlDir}* folder and start styling, + perhaps with the minimal styles shown below. + ++makeExcerpt('styles.css (excerpt)', 'quickstart') + +.callout.is-helpful + :marked + For the full set of master styles used by the documentation samples, + see [styles.css](https://github.com/angular/angular.io/blob/master/public/docs/_examples/styles.css). + +.l-main-section#build-and-run +h2 Step !{step++}: Build and run the app! +block run-app + :marked + Open a terminal window and enter this command: + code-example. + npm start + :marked + That command runs two parallel node processes + 1. The TypeScript compiler in watch mode + 1. A static server called **lite-server** that loads `index.html` in a browser + and refreshes the browser when application files change + + In a few moments, a browser tab should open and display + +figure.image-display + img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of QuickStart app") + +:marked + **Great job!** + +block build-app + //- Nothing for ts. + +:marked + ## Make some changes + + Try changing the message to "My SECOND Angular 2 app". +block server-watching + :marked + The TypeScript compiler and `lite-server` are watching. + They should detect the change, recompile the TypeScript into JavaScript, + refresh the browser, and display the revised message. + It's a nifty way to develop an application! + + We close the terminal window when we're done to terminate both the compiler and the server. + +.l-main-section +:marked + # Wrap up + + Our final project folder structure looks like this: +block project-file-structure + .filetree + .file angular2-quickstart + .children + .file app + .children + .file app.component.ts + .file app.module.ts + .file main.ts + .file node_modules ... + .file typings ... + .file index.html + .file package.json + .file styles.css + .file systemjs.config.js + .file tsconfig.json + .file typings.json +:marked + Here are the file contents: + +block project-files + +makeTabs(` + quickstart/ts/app/app.component.ts, + quickstart/ts/app/app.module.ts, + quickstart/ts/app/main.ts, + quickstart/ts/index.html, + quickstart/ts/package.1.json, + quickstart/ts/tsconfig.1.json, + quickstart/ts/typings.1.json, + quickstart/ts/styles.1.css, + quickstart/ts/systemjs.config.1.js` + , + ',,,,,,,,', + `app/app.component.ts, + app/app.module.ts, + app/main.ts, + index.html, + package.json, + tsconfig.json, + typings.json, + styles.css, + systemjs.config.js`) + +.l-main-section +:marked + ## What next? + Our first application doesn't do much. It's basically "Hello, World" for Angular 2. + + We kept it simple in our first pass: we wrote a little Angular component, + created a simple `index.html`, and launched with a + static file server. That's about all we'd expect to do for a "Hello, World" app. + + **We have greater ambitions!** ++ifDocsFor('ts') + :marked + The good news is that the overhead of setup is (mostly) behind us. + We'll probably only touch the `package.json` to update libraries. + We'll likely open `index.html` only if we need to add a library or some css stylesheets. +:marked + We're about to take the next step and build a small application that + demonstrates the great things we can build with Angular 2. + + Join us on the [Tour of Heroes Tutorial](./tutorial)! From 596b6862de72928d2d2d6cbf2abbdd48dee94c9b Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Thu, 11 Aug 2016 11:47:59 -0700 Subject: [PATCH 005/247] docs(template-syntax/dart): enhancements to example code (#2051) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(template-syntax/dart): enhancements to example code Enhancements to `NgStyle` section in support of its API docs. - Add feature supporting interactive update of a paragraph’s style. - Add full type declarations. - Replace bogus implementation of `getStyles()`. * dartfmt updates --- .../dart/lib/app_component.dart | 42 ++++++++++++++----- .../dart/lib/app_component.html | 12 ++++++ 2 files changed, 43 insertions(+), 11 deletions(-) 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 6d9199c175..26f2c82625 100644 --- a/public/docs/_examples/template-syntax/dart/lib/app_component.dart +++ b/public/docs/_examples/template-syntax/dart/lib/app_component.dart @@ -108,8 +108,7 @@ class AppComponent implements OnInit, AfterViewInit { bool onSave([UIEvent event = null]) { HtmlElement el = event?.target; - var evtMsg = - event != null ? ' Event target is ${el.innerHtml}.' : ''; + var evtMsg = event != null ? ' Event target is ${el.innerHtml}.' : ''; alerter('Saved. $evtMsg'); return false; } @@ -126,8 +125,12 @@ class AppComponent implements OnInit, AfterViewInit { } String getStyles(Element el) { - var showStyles = setStyles(); - return JSON.encode(showStyles); + final style = el.style; + final Map styles = {}; + for (var i = 0; i < style.length; i++) { + styles[style.item(i)] = style.getPropertyValue(style.item(i)); + } + return JSON.encode(styles); } Map _previousClasses = {}; @@ -140,8 +143,8 @@ class AppComponent implements OnInit, AfterViewInit { }; // #docregion setClasses // compensate for DevMode (sigh) - if (JSON.encode(_previousClasses) == - JSON.encode(classes)) return _previousClasses; + if (JSON.encode(_previousClasses) == JSON.encode(classes)) + return _previousClasses; _previousClasses = classes; // #enddocregion setClasses return classes; @@ -149,8 +152,8 @@ class AppComponent implements OnInit, AfterViewInit { // #enddocregion setClasses // #docregion setStyles - Map setStyles() { - return { + Map setStyles() { + return { 'font-style': canSave ? 'italic' : 'normal', // italic 'font-weight': !isUnchanged ? 'bold' : 'normal', // normal 'font-size': isSpecial ? '24px' : '8px' // 24px @@ -158,6 +161,20 @@ class AppComponent implements OnInit, AfterViewInit { } // #enddocregion setStyles + // #docregion NgStyle + bool isItalic = false; + bool isBold = false; + String fontSize = 'large'; + + Map setStyle() { + return { + 'font-style': isItalic ? 'italic' : 'normal', + 'font-weight': isBold ? 'bold' : 'normal', + 'font-size': fontSize + }; + } + // #enddocregion NgStyle + String title = 'Template Syntax'; String toeChoice; String toeChooser(Element picker) { @@ -187,13 +204,16 @@ class AppComponent implements OnInit, AfterViewInit { int heroesNoTrackByChangeCount = 0; int heroesWithTrackByChangeCount = 0; - @ViewChildren('noTrackBy') QueryList childrenNoTrackBy; - @ViewChildren('withTrackBy') QueryList childrenWithTrackBy; + @ViewChildren('noTrackBy') + QueryList childrenNoTrackBy; + @ViewChildren('withTrackBy') + QueryList childrenWithTrackBy; void _detectNgForTrackByEffects() { /// Converts [viewChildren] to a list of [Element]. List _extractChildren(QueryList viewChildren) => - viewChildren.toList()[0].nativeElement.children.toList() as List; + viewChildren.toList()[0].nativeElement.children.toList() + as List; { // Updates 'without TrackBy' statistics. 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 c7542c3039..5381bd4024 100644 --- a/public/docs/_examples/template-syntax/dart/lib/app_component.html +++ b/public/docs/_examples/template-syntax/dart/lib/app_component.html @@ -409,6 +409,18 @@ bindon-ngModel

    NgStyle Binding

    + +
    +

    Change style of this text!

    + + | + | + + +

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

    +
    + +
    This div is x-large. From de4114845788eefd6b3dfb9a382d18bd8c80c97a Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Thu, 11 Aug 2016 14:39:16 -0700 Subject: [PATCH 006/247] chore(cache): cache management script (#2090) Cf. #2088. --- scripts/cache.sh | 74 ++++++++++++++++++++++++++++++++++++++++ scripts/refresh-cache.sh | 44 ------------------------ 2 files changed, 74 insertions(+), 44 deletions(-) create mode 100755 scripts/cache.sh delete mode 100755 scripts/refresh-cache.sh diff --git a/scripts/cache.sh b/scripts/cache.sh new file mode 100755 index 0000000000..dda45285a9 --- /dev/null +++ b/scripts/cache.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +BASE="public/docs/ts" +LATEST="$BASE/latest" +CACHE="$BASE/_cache" + +FILES=" +guide/architecture.jade +guide/attribute-directives.jade +guide/component-styles.jade +guide/dependency-injection.jade +guide/displaying-data.jade +guide/hierarchical-dependency-injection.jade +guide/lifecycle-hooks.jade +guide/pipes.jade +guide/security.jade +guide/server-communication.jade +guide/structural-directives.jade +guide/template-syntax.jade +quickstart.jade +tutorial/toh-pt6.jade" + +function cacheRefresh() { + local FILE_PATTERN="*" + if [[ -n "$1" ]]; then + FILE_PATTERN="$1" + else + echo "Argument missing: specify shell file glob pattern of files to be refreshed." + exit 1; + fi + + local allFound=true; + + for f in $FILES; do + local srcPath="$LATEST/$f"; + local destPath="$CACHE/$f"; + local destDir=`dirname $destPath`; + if [[ -e $srcPath ]]; then + [[ -d "$destDir" ]] || (set -x; mkdir $destDir); + case "$f" in + ($FILE_PATTERN) + (set -x; cp $srcPath $destPath);; + (*) + echo "SKIPPED $f";; + esac + else + echo Cannot find $srcPath + allFound=false; + fi + done + + [[ $allFound ]] || exit 1; +} + +function cacheDiff() { + diff -qr -x "_*.*" "$CACHE/" "$LATEST/" | \ + grep -v "^Only in" +} + +function usage() { + echo "Usage: cache.sh [-d | -l | -r pattern]" + echo " -d diff cache and latest subdirectories" + echo " -l list files subject to caching" + echo " -r pat refresh files in cache matching pattern" +} + +case "$1" in + (-r) shift; cacheRefresh $@;; + (-d) shift; cacheDiff $@;; + (-l) shift; printf "$FILES\n\n";; + (*) usage; +esac diff --git a/scripts/refresh-cache.sh b/scripts/refresh-cache.sh deleted file mode 100755 index dccd79016f..0000000000 --- a/scripts/refresh-cache.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -set -e -o pipefail - -BASE="public/docs/ts" -LATEST="$BASE/latest" -CACHE="$BASE/_cache" - -FILES=" -guide/architecture.jade -guide/attribute-directives.jade -guide/component-styles.jade -guide/dependency-injection.jade -guide/displaying-data.jade -guide/hierarchical-dependency-injection.jade -guide/lifecycle-hooks.jade -guide/pipes.jade -guide/security.jade -guide/server-communication.jade -guide/structural-directives.jade -guide/template-syntax.jade -quickstart.jade -tutorial/toh-pt6.jade" - -function main() { - local allFound=true; - - for f in $FILES; do - local srcPath="$LATEST/$f"; - local destPath="$CACHE/$f"; - local destDir=`dirname $destPath`; - if [[ -e $srcPath ]]; then - [[ -d "$destDir" ]] || (set -x; mkdir $destDir); - (set -x; cp $srcPath $destPath) - else - echo Cannot find $srcPath - allFound=false; - fi - done - - [[ $allFound ]] || exit 1; -} - -main; From 7075cdbefa906c2301003df5d05624673ac29ac8 Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Thu, 11 Aug 2016 14:43:59 -0700 Subject: [PATCH 007/247] docs(hierarchical-di): post-RC5 Dart resync (#2080) Contributes to #2077. Depends on #2078. --- .../hierarchical-dependency-injection.jade | 37 +++++++++---------- .../hierarchical-dependency-injection.jade | 37 +++++++++---------- 2 files changed, 34 insertions(+), 40 deletions(-) diff --git a/public/docs/ts/_cache/guide/hierarchical-dependency-injection.jade b/public/docs/ts/_cache/guide/hierarchical-dependency-injection.jade index 6fcf422eda..f5bd734b41 100644 --- a/public/docs/ts/_cache/guide/hierarchical-dependency-injection.jade +++ b/public/docs/ts/_cache/guide/hierarchical-dependency-injection.jade @@ -8,7 +8,7 @@ block includes Angular has a Hierarchical Dependency Injection system. There is actually a tree of injectors that parallel an application's component tree. - We can re-configure the injectors at any level of that component tree with + We can reconfigure the injectors at any level of that component tree with interesting and useful results. In this chapter we explore these points and write some code. @@ -67,10 +67,10 @@ figure.image-display We'll reserve discussion of this option for another day. :marked Such a proliferation of injectors makes little sense until we consider the possibility that injectors at different levels can be - configured with different providers. We don't *have* to re-configure providers at every level. But we *can*. + configured with different providers. We don't *have* to reconfigure providers at every level. But we *can*. - If we don't re-configure, the tree of injectors appears to be flat. All requests bubble up to the root injector that we - configured with the `bootstrap` method. + If we don't reconfigure, the tree of injectors appears to be flat. All requests bubble up to the root + NgModule injector that we configured with the `!{_bootstrapModule}` method. The ability to configure one or more providers at different levels opens up interesting and useful possibilities. @@ -140,11 +140,14 @@ figure.image-display Look closely at the metadata for our `HeroEditComponent`. Notice the `providers` property. +makeExample('hierarchical-dependency-injection/ts/app/hero-editor.component.ts', 'providers') + +- var _root_NgModule = _docsFor == 'dart' ? 'bootstrap arguments' : 'root NgModule' :marked This adds a `RestoreService` provider to the injector of the `HeroEditComponent`. - Couldn’t we simply alter our bootstrap call to this? + Couldn’t we simply alter our !{_root_NgModule} to include this provider? + ++makeExcerpt(_appModuleTsVsMainTs, 'bad-alternative') -+makeExample('hierarchical-dependency-injection/ts/app/main.ts', 'bad-alternative') :marked Technically we could, but our component wouldn’t quite behave the way it is supposed to. Remember that each injector treats the services that it provides as singletons. However, in order to be able to have multiple instances of `HeroEditComponent` edit multiple heroes at the same time we need to have multiple instances of the `RestoreService`. More specifically, each instance of `HeroEditComponent` needs to be bound to its own instance of the `RestoreService`. @@ -159,20 +162,14 @@ figure.image-display we would have exactly one instance of that service and it would be shared across the entire application. That’s clearly not what we want in this scenario. We want each component to have its own instance of the `RestoreService`. - Defining (or re-defining) a provider at the component level creates a new instance of the service for each new instance + Defining (or redefining) a provider at the component level creates a new instance of the service for each new instance of that component. We've made the `RestoreService` a kind of "private" singleton for each `HeroEditComponent`, scoped to that component instance and its child components. - +//- ## Advanced Dependency Injection in Angular 2 +//- Restrict Dependency Lookups +//- [TODO] (@Host) This has been postponed for now until we come up with a decent use case +//- .l-main-section +//- :marked +//- ## Dependency Visibility +//- [TODO] (providers vs viewProviders) This has been postponed for now until come up with a decent use case diff --git a/public/docs/ts/latest/guide/hierarchical-dependency-injection.jade b/public/docs/ts/latest/guide/hierarchical-dependency-injection.jade index 84e0c6ab3f..f5bd734b41 100644 --- a/public/docs/ts/latest/guide/hierarchical-dependency-injection.jade +++ b/public/docs/ts/latest/guide/hierarchical-dependency-injection.jade @@ -8,7 +8,7 @@ block includes Angular has a Hierarchical Dependency Injection system. There is actually a tree of injectors that parallel an application's component tree. - We can re-configure the injectors at any level of that component tree with + We can reconfigure the injectors at any level of that component tree with interesting and useful results. In this chapter we explore these points and write some code. @@ -67,10 +67,10 @@ figure.image-display We'll reserve discussion of this option for another day. :marked Such a proliferation of injectors makes little sense until we consider the possibility that injectors at different levels can be - configured with different providers. We don't *have* to re-configure providers at every level. But we *can*. + configured with different providers. We don't *have* to reconfigure providers at every level. But we *can*. - If we don't re-configure, the tree of injectors appears to be flat. All requests bubble up to the root NgModule injector that we - configured with the `bootstrapModule` method. + If we don't reconfigure, the tree of injectors appears to be flat. All requests bubble up to the root + NgModule injector that we configured with the `!{_bootstrapModule}` method. The ability to configure one or more providers at different levels opens up interesting and useful possibilities. @@ -140,11 +140,14 @@ figure.image-display Look closely at the metadata for our `HeroEditComponent`. Notice the `providers` property. +makeExample('hierarchical-dependency-injection/ts/app/hero-editor.component.ts', 'providers') + +- var _root_NgModule = _docsFor == 'dart' ? 'bootstrap arguments' : 'root NgModule' :marked This adds a `RestoreService` provider to the injector of the `HeroEditComponent`. - Couldn’t we simply alter our root NgModule to include this provider? + Couldn’t we simply alter our !{_root_NgModule} to include this provider? + ++makeExcerpt(_appModuleTsVsMainTs, 'bad-alternative') -+makeExample('hierarchical-dependency-injection/ts/app/app.module.ts', 'bad-alternative') :marked Technically we could, but our component wouldn’t quite behave the way it is supposed to. Remember that each injector treats the services that it provides as singletons. However, in order to be able to have multiple instances of `HeroEditComponent` edit multiple heroes at the same time we need to have multiple instances of the `RestoreService`. More specifically, each instance of `HeroEditComponent` needs to be bound to its own instance of the `RestoreService`. @@ -159,20 +162,14 @@ figure.image-display we would have exactly one instance of that service and it would be shared across the entire application. That’s clearly not what we want in this scenario. We want each component to have its own instance of the `RestoreService`. - Defining (or re-defining) a provider at the component level creates a new instance of the service for each new instance + Defining (or redefining) a provider at the component level creates a new instance of the service for each new instance of that component. We've made the `RestoreService` a kind of "private" singleton for each `HeroEditComponent`, scoped to that component instance and its child components. - +//- ## Advanced Dependency Injection in Angular 2 +//- Restrict Dependency Lookups +//- [TODO] (@Host) This has been postponed for now until we come up with a decent use case +//- .l-main-section +//- :marked +//- ## Dependency Visibility +//- [TODO] (providers vs viewProviders) This has been postponed for now until come up with a decent use case From b772079bc9a08b4fb39e12668fa60d3aea5c75b4 Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Thu, 11 Aug 2016 17:44:42 -0700 Subject: [PATCH 008/247] chore(install): fix install scripts & improve local usage (#2041) Fix a few minor problems with Travis install & build scripts. Other changes allow `before-install.sh` to be run locally. --- scripts/before-install.sh | 8 +++----- scripts/env-info-and-check.sh | 4 +++- scripts/env-set.sh | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/before-install.sh b/scripts/before-install.sh index b99455e910..84b7ff8035 100755 --- a/scripts/before-install.sh +++ b/scripts/before-install.sh @@ -2,13 +2,11 @@ set -e -o pipefail -./scripts/env-info-and-check.sh +[[ -z "$NGIO_ENV_DEFS" ]] && . ./scripts/env-set.sh +[[ -n "$TRAVIS" ]] && . ./scripts/env-info-and-check.sh -if [[ 0 ]]; then - # Doesn't seem to be necessary. Disabling. - travis_fold start install.globals +if [ -z "$TRAVIS" ]; then set -x npm install -g gulp --no-optional set +x - travis_fold end install.globals fi diff --git a/scripts/env-info-and-check.sh b/scripts/env-info-and-check.sh index c919602f10..3442dc80e1 100755 --- a/scripts/env-info-and-check.sh +++ b/scripts/env-info-and-check.sh @@ -2,6 +2,8 @@ set -e -o pipefail +[[ -z "$NGIO_ENV_DEFS" ]] && . ./scripts/env-set.sh + travis_fold start env_info echo ENVIRONMENT INFO travis_fold start env_info.path @@ -11,7 +13,7 @@ echo travis_fold end env_info.path travis_fold start env_info.home echo Home: $HOME -ls ~ -la +ls -la ~ echo travis_fold end env_info.home travis_fold start env_info.pwd diff --git a/scripts/env-set.sh b/scripts/env-set.sh index 8341107a8c..89a3e5392e 100644 --- a/scripts/env-set.sh +++ b/scripts/env-set.sh @@ -3,7 +3,7 @@ if [[ -z "$NGIO_ENV_DEFS" ]]; then export ANSI_YELLOW="\033[33;1m" export ANSI_RESET="\033[0m" - echo -e "${ANSI_YELLOW}Setting environment variables from scripts/env.sh${ANSI_RESET}" + echo -e "${ANSI_YELLOW}Setting environment variables from scripts/env-set.sh${ANSI_RESET} " export NGIO_ENV_DEFS=1 @@ -12,7 +12,7 @@ if [[ -z "$NGIO_ENV_DEFS" ]]; then if [ ! $(type -t travis_fold) ]; then # In case this is being run locally. Turn travis_fold into a noop. - travis_fold () { return; } + travis_fold () { true; } # Alternative definition: # travis_fold () { echo -en "travis_fold:${1}:${2}"; } fi From a771a6e0d05364160902b2e5bb421100bd55fc32 Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Fri, 12 Aug 2016 11:14:44 -0700 Subject: [PATCH 009/247] chore(ts/cache): add glossary (#2098) --- public/docs/ts/_cache/glossary.jade | 700 ++++++++++++++++++++++++++++ scripts/cache.sh | 1 + 2 files changed, 701 insertions(+) create mode 100644 public/docs/ts/_cache/glossary.jade diff --git a/public/docs/ts/_cache/glossary.jade b/public/docs/ts/_cache/glossary.jade new file mode 100644 index 0000000000..50c6100cda --- /dev/null +++ b/public/docs/ts/_cache/glossary.jade @@ -0,0 +1,700 @@ +include _util-fns + +// #docregion intro +:marked + # Angular 2 Glossary + + Angular 2 has a vocabulary of its own. + Most Angular 2 terms are everyday English words + with a specific meaning within the Angular system. + + We have gathered here the most prominent terms + and a few less familiar ones that have unusual or + unexpected definitions. + + [A](#A) [B](#B) [C](#C) [D](#D) [E](#E) [F](#F) [G](#G) [H](#H) [I](#I) + [J](#J) [K](#K) [L](#L) [M](#M) [N](#N) [O](#O) [P](#P) [Q](#Q) [R](#R) + [S](#S) [T](#T) [U](#U) [V](#V) [W](#W) [X](#X) [Y](#Y) [Z](#Z) +// #enddocregion intro + +// #docregion a1 + +// #enddocregion a1 +.l-main-section +:marked + ## Annotation +.l-sub-section + :marked + In practice a synonym for [Decoration](#decorator). +// #enddocregion a-1 +// #docregion a-2 +:marked + ## Attribute Directive +.l-sub-section + :marked + A category of [Directive](#directive) that can listen to and modify the behavior of + other HTML elements, attributes, properties, and components. They are usually represented + as HTML attributes, hence the name. + + The `ngClass` directive for adding and removing CSS class names is a good example of + an Attribute Directive. +// #enddocregion a-2 + +// #docregion b-c +- var lang = current.path[1] +- var decorator = lang === 'dart' ? 'annotation' : 'decorator' +- var atSym = lang === 'js' ? '' : '@' + +.l-main-section +:marked + ## Barrel +.l-sub-section + :marked + A barrel is a way to *rollup exports* from several modules into a single convenience module. + The barrel itself is a module file that re-exports *selected* exports of other modules. + + Imagine three modules in a `heroes` folder: + code-example. + // heroes/hero.component.ts + export class HeroComponent {} + + // heroes/hero.model.ts + export class Hero {} + + // heroes/hero.service.ts + export class HeroService {} + :marked + Without a barrel, a consumer would need three import statements: + code-example. + import { HeroComponent } from '../heroes/hero.component.ts'; + import { Hero } from '../heroes/hero.model.ts'; + import { HeroService } from '../heroes/hero.service.ts'; + :marked + We can add a barrel to the `heroes` folder (called `index` by convention) that exports all of these items: + code-example. + export * from './hero.model.ts'; // re-export all of its exports + export * from './hero.service.ts'; // re-export all of its exports + export { HeroComponent } from './hero.component.ts'; // re-export the named thing + :marked + Now a consumer can import what it needs from the barrel. + code-example. + import { Hero, HeroService } from '../heroes'; // index is implied + :marked + The Angular [scoped packages](#scoped-package) each have a barrel named `index`. +// #enddocregion b-c +:marked + That's why we can write this: ++makeExcerpt('quickstart/ts/app/app.component.ts', 'import', '') +// #docregion b-c + +:marked + ## Binding +.l-sub-section + :marked + Almost always refers to [Data Binding](#data-binding) and the act of + binding an HTML object property to a data object property. + + May refer to a [Dependency Injection](#dependency-injection) binding + between a "token" or "key" and a dependency [provider](#provider). + This more rare usage should be clear in context. + +:marked + ## Bootstrap +.l-sub-section + :marked + We launch an Angular application by "bootstrapping" it with the `bootstrap` method. + The `bootstrap` method identifies an application's top level "root" [Component](#component) + and optionally registers service [providers](#provider) with the + [dependency injection system](#dependency-injection). + + One can bootstrap multiple apps in the same `index.html`, each with its own top level root. + + +.l-main-section +:marked + ## camelCase +.l-sub-section + :marked + The practice of writing compound words or phrases such that each word or abbreviation begins with a capital letter + _except the first letter which is a lowercase letter_. + + Function, property, and method names are typically spelled in camelCase. Examples include: `square`, `firstName` and `getHeroes`. + + This form is also known as **lower camel case**, to distinguish it from **upper camel case** which we call [PascalCase](#pascalcase). + When we write "camelCase" in this documentation we always mean *lower camel case*. + +:marked + ## Component +.l-sub-section + :marked + An Angular class responsible for exposing data + to a [View](#view) and handling most of the view’s display + and user-interaction logic. + + The Component is one of the most important building blocks in the Angular system. + It is, in fact, an Angular [Directive](#directive) with a companion [Template](#template). + + The developer applies the `#{atSym}Component` !{decorator} to + the component class, thereby attaching to the class the essential component metadata + that Angular needs to create a component instance and render it with its template + as a view. + + Those familiar with "MVC" and "MVVM" patterns will recognize + the Component in the role of "Controller" or "View Model". +// #enddocregion b-c + +// #docregion d1 + +.l-main-section +:marked + ## dash-case +.l-sub-section + :marked + The practice of writing compound words or phrases such that each word is separated by a dash or hyphen (`-`). + + Directive selectors and the root of filenames are often spelled in dash-case. Examples include: `my-app` and `hero-list.component.ts`. + + This form is also known as [kebab-case](#kebab-case). + +:marked + ## Data Binding +.l-sub-section + :marked + Applications display data values to a user and respond to user + actions (clicks, touches, keystrokes). + + We could push application data values into HTML, attach + event listeners, pull changed values from the screen, and + update application data values ... all by hand. + + Or we could declare the relationship between an HTML widget + and an application data source ... and let a data binding + framework handle the details. + + Data Binding is that second approach. Angular has a rich + data binding framework with a variety of data binding + operations and supporting declaration syntax. + + The many forms of binding include: + * [Interpolation](/docs/ts/latest/guide/template-syntax.html#interpolation) + * [Property Binding](/docs/ts/latest/guide/template-syntax.html#property-binding) + * [Event Binding](/docs/ts/latest/guide/template-syntax.html#event-binding) + * [Attribute Binding](/docs/ts/latest/guide/template-syntax.html#attribute-binding) + * [Class Binding](/docs/ts/latest/guide/template-syntax.html#class-binding) + * [Style Binding](/docs/ts/latest/guide/template-syntax.html#style-binding) + * [Two-way data binding with ngModel](/docs/ts/latest/guide/template-syntax.html#ng-model) + + Learn more about data binding in the + [Template Syntax](/docs/ts/latest/guide/template-syntax.html#data-binding) chapter. + +// #enddocregion d1 + +:marked + ## Decorator | Decoration +.l-sub-section + :marked + A Decorator is a **function** that adds metadata to a class, its members (properties, methods) and function arguments. + + Decorators are a JavaScript language [feature](https://github.com/wycats/javascript-decorators), implemented in TypeScript and proposed for ES2016 (AKA ES7). + + We apply a decorator by positioning it + immediately above or to the left of the thing it decorates. + + Angular has its own set of decorators to help it interoperate with our application parts. + Here is an example of a `@Component` decorator that identifies a + class as an Angular [Component](#component) and an `@Input` decorator applied to a property + of that component. + The elided object argument to the `@Component` decorator would contain the pertinent component metadata. + ``` + @Component({...}) + export class AppComponent { + constructor(@Inject('SpecialFoo') public foo:Foo) {} + @Input() name:string; + } + ``` + The scope of a decorator is limited to the language feature + that it decorates. None of the decorations shown here will "leak" to other + classes appearing below it in the file. + + .alert.is-important + :marked + Always include the parentheses `()` when applying a decorator. + A decorator is a **function** that must be called when applied. + +// #docregion d2 +:marked + ## Dependency Injection +.l-sub-section + :marked + Dependency Injection is both a design pattern and a mechanism + for creating and delivering parts of an application to other + parts of an application that request them. + + Angular developers prefer to build applications by defining many simple parts + that each do one thing well and then wire them together at runtime. + + These parts often rely on other parts. An Angular [Component](#component) + part might rely on a service part to get data or perform a calculation. When a + part "A" relies on another part "B", we say that "A" depends on "B" and + that "B" is a dependency of "A". + + We can ask a "Dependency Injection System" to create "A" + for us and handle all the dependencies. + If "A" needs "B" and "B" needs "C", the system resolves that chain of dependencies + and returns a fully prepared instance of "A". + + Angular provides and relies upon its own sophisticated + [Dependency Injection](dependency-injection.html) system + to assemble and run applications by "injecting" application parts + into other application parts where and when needed. + + At the core there is an [`Injector`](#injector) that returns dependency values on request. + The expression `injector.get(token)` returns the value associated with the given token. + + A token is an Angular type (`OpaqueToken`). We rarely deal with tokens directly; most + methods accept a class name (`Foo`) or a string ("foo") and Angular converts it + to a token. When we write `injector.get(Foo)`, the injector returns + the value associated with the token for the `Foo` class, typically an instance of `Foo` itself. + + Angular makes similar requests internally during many of its operations + as when it creates a [`Component`](#component) for display. + + The `Injector` maintains an internal map of tokens to dependency values. + If the `Injector` can't find a value for a given token, it creates + a new value using a `Provider` for that token. + + A [Provider](#provider) is a recipe for + creating new instances of a dependency value associated with a particular token. + + An injector can only create a value for a given token if it has + a `Provider` for that token in its internal provider registry. + Registering providers is a critical preparatory step. + + Angular registers some of its own providers with every injector. + We can register our own providers. Quite often the best time to register a `Provider` + is when we [bootstrap](#bootstrap) the application. + There are other opportunities to register as well. + + Learn more in the [Dependency Injection](/docs/ts/latest/guide/dependency-injection.html) chapter. +:marked + ## Directive +.l-sub-section + :marked + An Angular class responsible for creating, re-shaping, and interacting with HTML elements + in the browser DOM. Directives are Angular's most fundamental feature. + + A Directive is almost always associated with an HTML element or attribute. + We often refer to such an element or attribute as the directive itself. + When Angular finds a directive in an HTML template, + it creates the matching directive class instance + and gives that instance control over that portion of the browser DOM. + + Developers can invent custom HTML markup (e.g., ``) to + associate with their custom directives. They add this custom markup to HTML templates + as if they were writing native HTML. In this way, directives become extensions of + HTML itself. + + Directives fall into one of three categories: + + 1. [Components](#component) that combine application logic with an HTML template to + render application [views]. Components are usually represented as HTML elements. + They are the building blocks of an Angular application and the + developer can expect to write a lot of them. + + 1. [Attribute Directives](#attribute-directive) that can listen to and modify the behavior of + other HTML elements, attributes, properties, and components. They are usually represented + as HTML attributes, hence the name. + + 1. [Structural Directives](#structural-directive), a directive responsible for + shaping or re-shaping HTML layout, typically by adding, removing, or manipulating + elements and their children. +// #enddocregion d2 + +// #docregion e1 + +// #enddocregion e1 +// #docregion e2 +.l-main-section +:marked + ## ECMAScript +.l-sub-section + :marked + The [official JavaScript language specification](https://en.wikipedia.org/wiki/ECMAScript). + + The latest approved version of JavaScript is + [ECMAScript 2015](http://www.ecma-international.org/ecma-262/6.0/) + (AKA "ES2015" or "ES6") and many Angular 2 developers will write their applications + either in this version of the language or a dialect that strives to be + compatible with it such as [TypeScript](#typesScript). + + Most modern browsers today only support the prior "ECMAScript 5" (AKA ES5) standard. + Applications written in ES2015 or one of its dialects must be "[transpiled](#transpile)" + to ES5 JavaScript. + + Angular 2 developers may choose to write in ES5 directly. +:marked + ## ECMAScript 2015 +.l-sub-section + :marked + The latest released version of JavaScript, + [ECMAScript 2015](http://www.ecma-international.org/ecma-262/6.0/) + (AKA "ES2015" or "ES6") +:marked + ## ES2015 +.l-sub-section + :marked + Short hand for "[ECMAScript 2015](#ecmascript=2015)". +:marked + ## ES6 +.l-sub-section + :marked + Short hand for "[ECMAScript 2015](#ecmascript=2015)". +:marked + ## ES5 +.l-sub-section + :marked + Short hand for "ECMAScript 5", the version of JavaScript run by most modern browsers. + See [ECMAScript](#ecmascript). +// #enddocregion e2 + +// #docregion f-l + + + + +.l-main-section +:marked + ## Injector +.l-sub-section + :marked + An object in the Angular [dependency injection system](#dependency-injection) + that can find a named "dependency" in its cache or create such a thing + with a registered [provider](#provider). + +:marked + ## Input +.l-sub-section + :marked + A directive property that can be the ***target*** of a + [Property Binding](/docs/ts/latest/guide/template-syntax.html#property-binding). + Data values flow *into* this property from the data source identified + in the template expression to the right of the equal sign. + + See the [Template Syntax](/docs/ts/latest/guide/template-syntax.html#inputs-outputs) chapter. + +:marked + ## Interpolation +.l-sub-section + :marked + A form of [Property Data Binding](#data-binding) in which a + [template expression](#template-expression) between double-curly braces + renders as text. That text may be concatenated with neighboring text + before it is assigned to an element property + or displayed between element tags as in this example. + + code-example(language="html" escape="html"). + + + :marked + Learn more about interpolation in the + [Template Syntax](/docs/ts/latest/guide/template-syntax.html#interpolation) chapter. + + + + +.l-main-section + +:marked + ## kebab-case +.l-sub-section + :marked + The practice of writing compound words or phrases such that each word is separated by a dash or hyphen (`-`). + + Directive selectors and the root of filenames are often spelled in kebab-case. Examples include: `my-app` and `hero-list.component.ts`. + + This form is also known as [dash-case](#dash-case). + + +.l-main-section +:marked + ## Lifecycle Hooks +.l-sub-section + :marked + [Directives](#directive) and [Components](#component) have a lifecycle + managed by Angular as it creates, updates and destroys them. + + Developers can tap into key moments in that lifecycle by implementing + one or more of the "Lifecycle Hook" interfaces. + + Each interface has a single hook method whose name is the interface name prefixed with `ng`. + For example, the `OnInit` interface has a hook method names `ngOnInit`. + + Angular calls these hook methods in the following order: + * `ngOnChanges` - called when an [input](#input)/[output](#output) binding values change + * `ngOnInit` - after the first `ngOnChanges` + * `ngDoCheck` - developer's custom change detection + * `ngAfterContentInit` - after component content initialized + * `ngAfterContentChecked` - after every check of component content + * `ngAfterViewInit` - after component's view(s) are initialized + * `ngAfterViewChecked` - after every check of a component's view(s) + * `ngOnDestroy` - just before the directive is destroyed. + + Learn more in the [Lifecycle Hooks](/docs/ts/latest/guide/lifecycle-hooks.html) chapter. +// #enddocregion f-l + +// #docregion m1 + +// #enddocregion m1 +// #docregion m2 +.l-main-section +:marked + ## Module +.l-sub-section + :marked + Angular apps are modular. + + In general, we assemble our application from many modules, both the ones we write ourselves + and the ones we acquire from others. + + A typical module is a cohesive block of code dedicated to a single purpose. + + A module **exports** something of value in that code, typically one thing such as a class. + A module that needs that thing, **imports** it. + + The structure of Angular modules and the import/export syntax + is based on the [ES2015](#es2015) module standard + described [here](http://www.2ality.com/2014/09/es6-modules-final.html). + + An application that adheres to this standard requires a module loader to + load modules on request and resolve inter-module dependencies. + Angular does not ship with a module loader and does not have a preference + for any particular 3rd party library (although most samples use SystemJS). + Application developers may pick any module library that conforms to the standard + + Modules are typically named after the file in which the exported thing is defined. + The Angular [DatePipe](https://github.com/angular/angular/blob/master/modules/@angular/common/src/pipes/date_pipe.ts) + class belongs to a feature module named `date_pipe` in the file `date_pipe.ts`. + + Developers rarely access Angular feature modules directly. + We usually import them from one of the Angular [scoped packages](#scoped-package) such as `@angular/core`. + +// #enddocregion m2 + +// #docregion n-s-1 +- var lang = current.path[1] +- var decorator = lang === 'dart' ? 'annotation' : 'decorator' +- var atSym = lang === 'js' ? '' : '@' + + +.l-main-section +:marked + ## Output +.l-sub-section + :marked + A directive property that can be the ***target*** of an + [Event Binding](/docs/ts/latest/guide/template-syntax.html#property-binding). + Events stream *out* of this property to the receiver identified + in the template expression to the right of the equal sign. + + See the [Template Syntax](/docs/ts/latest/guide/template-syntax.html#inputs-outputs) chapter. + +.l-main-section + +:marked + ## PascalCase +.l-sub-section + :marked + The practice of writing compound words or phrases such that each word or abbreviation begins with a capital letter. + Class names are typically spelled in PascalCase. Examples include: `Person` and `Customer`. + + This form is also known as **upper camel case**, to distinguish it from **lower camel case** which we simply call [camelCase](#camelcase). + In this documentation, "PascalCase" means *upper camel case* and "camelCase" means *lower camel case*. + +:marked + ## Pipe +.l-sub-section + :marked + An Angular pipe is a function that transforms input values to output values for + display in a [view](#view). We use the `#{atSym}Pipe` !{decorator} + to associate the pipe function with a name. We then can use that + name in our HTML to declaratively transform values on screen. + + Here's an example that uses the built-in `currency` pipe to display + a numeric value in the local currency. + + code-example(language="html" escape="html"). + {{product.price | currency}} + :marked + Learn more in the chapter on [pipes](/docs/ts/latest/guide/pipes.html) . + +:marked + ## Provider +.l-sub-section + :marked + A Provider creates a new instance of a dependency for the Dependency Injection system. + It relates a lookup token to code - sometimes called a "recipe" - that can create a dependency value. + + For example, `new Provider(Foo, {useClass: Foo})` creates a `Provider` + that relates the `Foo` token to a function that creates a new instance of the `Foo` class. + + There are other ways to create tokens and recipes. + See [Dependency Injection](#dependency-injection) chapter to learn more. + +.l-main-section + + +:marked + ## Router +.l-sub-section + :marked + Most applications consist of many screens or [views](#view). + The user navigates among them by clicking links and buttons + and taking other similar actions that cause the application to + replace one view with another. + + The Angular [Component Router](/docs/ts/latest/guide/router.html) is a richly featured mechanism for configuring + and managing the entire view navigation process including the creation and destruction + of views. +:marked + ## Routing Component +.l-sub-section + :marked + A [Component](#component) with an attached router. + + In most cases, the component became attached to a [router](#router) by means + of a `#{atSym}RouterConfig` #{decorator} that defined routes to views controlled by this component. + + The component's template has a `RouterOutlet` element where it can display views produced by the router. + + It likely has anchor tags or buttons with `RouterLink` directives that users can click to navigate. + + +.l-main-section +// #enddocregion n-s-1 +:marked + ## Scoped Package +.l-sub-section + :marked + Angular modules are delivered within *scoped packages* such as `@angular/core`, `@angular/common`, `@angular/platform-browser-dynamic`, + `@angular/http`, and `@angular/router`. + + A [*scoped package*](https://docs.npmjs.com/misc/scope) is a way to group related *npm* packages. + + We import a scoped package the same way we'd import a *normal* package. + The only difference, from a consumer perspective, + is that the package name begins with the Angular *scope name*, `@angular`. + + +makeExcerpt('architecture/ts/app/app.component.ts', 'import', '') +// #docregion n-s-2 + +:marked + ## Structural Directive +.l-sub-section + :marked + A category of [Directive](#directive) that can + shape or re-shape HTML layout, typically by adding, removing, or manipulating + elements and their children. + + The `ngIf` "conditional element" directive and the `ngFor` "repeater" directive are + good examples in this category. +// #enddocregion n-s-2 + +// #docregion t1 + +.l-main-section +:marked + ## Template +.l-sub-section + :marked + A template is a chunk of HTML that Angular uses to render a [view](#view) with + the support and continuing guidance of an Angular [Directive](#directive), + most notably a [Component](#component). + + We write templates in a special [Template Syntax](/docs/ts/latest/guide/template-syntax.html). + +:marked + ## Template Expression +.l-sub-section + :marked + An expression in a JavaScript-like syntax that Angular evaluates within + a [data binding](#data-binding). Learn how to write template expressions + in the [Template Syntax](/docs/ts/latest/guide/template-syntax.html#template-expressions) chapter. + +// #enddocregion t1 +// #docregion t2 +:marked + ## Transpile +.l-sub-section + :marked + The process of transforming code written in one form of JavaScript + (e.g., TypeScript) into another form of JavaScript (e.g., [ES5](#es5)). + + :marked + ## TypeScript +.l-sub-section + :marked + A version of JavaScript that supports most [ECMAScript 2015](#ecmascript=2015) + language features and many features that may arrive in future versions + of JavaScript such as [Decorators](#decorator). + + TypeScript is also noteable for its optional typing system which gives + us compile-time type-checking and strong tooling support (e.g. "intellisense", + code completion, refactoring, and intelligent search). Many code editors + and IDEs support TypeScript either natively or with plugins. + + TypeScript is the preferred language for Angular 2 development although + we are welcome to write in other JavaScript dialects such as [ES5](#es5). + + Angular 2 itself is written in TypeScript. + + Learn more about TypeScript on its [website](http://www.typescriptlang.org/). +// #enddocregion t2 + +// #docregion u-z + + +.l-main-section +:marked + ## View +.l-sub-section + :marked + A view is a portion of the screen that displays information and responds + to user actions such as clicks, mouse moves, and keystrokes. + + Angular renders a view under the control of one or more [Directives](#directive), + especially [Component](#component) directives and their companion [Templates](#template). + The Component plays such a prominent role that we often + find it convenient to refer to a component as a view. + + Views often contain other views and any view might be loaded and unloaded + dynamically as the user navigates through the application, typically + under the control of a [router](#router). + +.l-main-section + + + + +:marked + ## Zone +.l-sub-section + :marked + Zones are a mechanism for encapsulating and intercepting + a JavaScript application's asynchronous activity. + + The browser DOM and JavaScript have a limited number + of asynchronous activities, activities such as DOM events (e.g., clicks), + [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise), and + [XHR](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) + calls to remote servers. + + Zones intercept all of these activities and give a "zone client" the opportunity + to take action before and after the async activity completes. + + Angular runs our application in a zone where it can respond to + asynchronous events by checking for data changes and updating + the information it displays via [data binding](#data-binding). + + Learn more about zones in this + [Brian Ford video](https://www.youtube.com/watch?v=3IqtmUscE_U). +// #enddocregion u-z diff --git a/scripts/cache.sh b/scripts/cache.sh index dda45285a9..1c1ad7c351 100755 --- a/scripts/cache.sh +++ b/scripts/cache.sh @@ -19,6 +19,7 @@ guide/security.jade guide/server-communication.jade guide/structural-directives.jade guide/template-syntax.jade +glossary.jade quickstart.jade tutorial/toh-pt6.jade" From ea457825b801df36d1b4816fbc465dde7d794a5e Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Fri, 12 Aug 2016 11:20:44 -0700 Subject: [PATCH 010/247] docs(router): fix markdown, and example mixin cleanup (#2101) * docs(router): fix markdown and example mixin cleanup - Fixed: markdown text not under `:marked` region (and so that text was not showing up in the generated html). - Fixed: code excerpt title `constructor` -> `isSelected`. - Cleanup of all makeExample mixin uses. This cleanup will help make it easier to record differences with the deprecated router chapter (which must have app-relative makeExample paths). * post-review updates Found another instance of markdown (a heading) outside of a `:marked` region. --- public/_includes/_util-fns.jade | 6 +- public/docs/ts/latest/guide/router.jade | 334 ++++++++++++++++-------- 2 files changed, 231 insertions(+), 109 deletions(-) diff --git a/public/_includes/_util-fns.jade b/public/_includes/_util-fns.jade index c36f405145..cf9a569346 100644 --- a/public/_includes/_util-fns.jade +++ b/public/_includes/_util-fns.jade @@ -98,14 +98,14 @@ mixin makeExample(_filePath, region, _title, stylePatterns) //- ending is given or is just (), then the title will be suffixed with //- either "(excerpt)", or "(#{_region})" when _region is defined. mixin makeExcerpt(_filePath, _region, _title, stylePatterns) - - var matches = _filePath.match(/(.*)\s+\(([\w ]*)\)$/); + - var matches = _filePath.match(/(.*)\s+\(([^\)]*)\)$/); - var parenText; - if (matches) { _filePath = matches[1]; parenText = matches[2]; } - var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title}); - var filePath = adjustments.filePath; - var title = adjustments.title; - - var region = _region || parenText; - - var excerpt = !region || parenText === '' ? 'excerpt' : parenText || region; + - var region = _region || (_region === '' ? '' : parenText); + - var excerpt = parenText || region || 'excerpt'; - if (title) title = title + ' (' + excerpt + ')'; +makeExample(filePath, region, title, stylePatterns)(format='.') diff --git a/public/docs/ts/latest/guide/router.jade b/public/docs/ts/latest/guide/router.jade index 24ac0e5bad..37fefe40f7 100644 --- a/public/docs/ts/latest/guide/router.jade +++ b/public/docs/ts/latest/guide/router.jade @@ -72,7 +72,8 @@ include ../_util-fns If the `app` folder is the application root, as it is for our sample application, set the `href` value *exactly* as shown here. -+makeExample('router/ts/index.1.html','base-href', 'index.html (base href)')(format=".") + ++makeExcerpt('index.1.html', 'base-href') :marked ### Router imports @@ -80,7 +81,8 @@ include ../_util-fns It is not part of the Angular 2 core. It is in its own library package, `@angular/router`. We import what we need from it as we would from any other Angular package. -+makeExample('router/ts/app/app.routing.ts','import-router', 'app/app.routing.ts (import)')(format=".") ++makeExcerpt('app/app.routing.ts (import)', 'import-router') + .l-sub-section :marked We cover other options in the [details below](#browser-url-styles). @@ -93,7 +95,8 @@ include ../_util-fns We bootstrap our application with an array of routes that we'll provide to our **`RouterModule.forRoot`** function. In the following example, we configure our application with four route definitions. -+makeExample('router/ts/app/app.routing.1.ts','route-config','app/app.routing.ts')(format='.') + ++makeExcerpt('app/app.routing.1.ts (excerpt)', 'route-config') .l-sub-section :marked @@ -122,13 +125,15 @@ include ../_util-fns a configured *Router* module to our root NgModule imports. :marked Next we open `app.module.ts` where we must register our routing, routing providers, and declare our two route components. -+makeExample('router/ts/app/app.module.1.ts','router-basics','app/app.module.ts (basic setup)')(format='.') + ++makeExcerpt('app/app.module.1.ts (basic setup)', 'router-basics') + :marked ### Router Outlet Given this configuration, when the browser URL for this application becomes `/heroes`, the router matches that URL to the `Route` path `/heroes` and displays the `HeroListComponent` in a **`RouterOutlet`** that we've placed in the host view's HTML. -code-example(format="", language="html"). +code-example(language="html"). <!-- Routed views go here --> <router-outlet></router-outlet> :marked @@ -150,7 +155,9 @@ code-example(format="", language="html"). or on its parent element. We see such bindings in the following `AppComponent` template: -+makeExample('router/ts/app/app.component.1.ts', 'template')(format=".") + ++makeExcerpt('app/app.component.1.ts', 'template', '') + .l-sub-section :marked We're adding two anchor tags with `RouterLink` and `RouterLinkActive` directives. @@ -257,6 +264,7 @@ table We gloss over everything in between. The full source is available in the . + :marked Our client is the Hero Employment Agency. Heroes need work and The Agency finds Crises for them to solve. @@ -336,7 +344,7 @@ figure.image-display figure.image-display img(src='/resources/images/devguide/router/router-1-anim.gif' alt="App in action" ) - +a#base-href :marked ### Set the *<base href>* The Component Router uses the browser's @@ -356,7 +364,8 @@ figure.image-display If the `app` folder is the application root, as it is for our application, set the `href` value in **`index.html`** *exactly* as shown here. -+makeExample('router/ts/index.1.html','base-href', 'index.html (base href)')(format=".") ++makeExcerpt('index.1.html', 'base-href') + .l-sub-section :marked HTML 5 style navigation is the Component Router default. @@ -398,7 +407,7 @@ figure.image-display which returns a module containing the configured `Router` service provider ... and some other, unseen providers that the routing library requires. We export this as the `routing` token. -+makeExample('router/ts/app/app.routing.2.ts','', 'app/app.routing.ts')(format=".") ++makeExcerpt('app/app.routing.2.ts') .l-sub-section :marked @@ -443,7 +452,9 @@ h4#register-providers Register routing in the root NgModule so they will be registered within our root NgModule. We also import the `appRoutingProviders` array and add it to the `providers` array. -+makeExample('router/ts/app/app.module.1.ts','', 'app.module.ts')(format=".") + ++makeExcerpt('app/app.module.1.ts') + :marked Providing the router module in our root NgModule makes the Router available everywhere in our application. @@ -457,10 +468,13 @@ figure.image-display a#shell-template :marked The corresponding component template looks like this: -+makeExample('router/ts/app/app.component.1.ts','template')(format=".") -h3#router-outlet RouterOutlet ++makeExcerpt('app/app.component.1.ts', 'template', '') + +a#router-outlet :marked + ### *RouterOutlet* + `RouterOutlet` is a component from the router library. The router displays views within the bounds of the `` tags. @@ -469,8 +483,10 @@ h3#router-outlet RouterOutlet A template may hold exactly one ***unnamed*** ``. The router supports multiple *named* outlets, a feature we'll cover in future. -h3#router-link RouterLink binding +a#router-link :marked + ### *RouterLink* binding + Above the outlet, within the anchor tags, we see [Property Bindings](template-syntax.html#property-binding) to the `RouterLink` directive that look like `routerLink="..."`. We imported `RouterLink` from the router library. @@ -506,7 +522,8 @@ h3#router-directives Router Directives They are readily available for us to use in our template. :marked The current state of `app.component.ts` looks like this: -+makeExample('router/ts/app/app.component.1.ts','', 'app/app.component.ts')(format=".") + ++makeExcerpt('app/app.component.1.ts') :marked ### "Getting Started" wrap-up @@ -545,6 +562,7 @@ h3#router-directives Router Directives .file typings.json :marked Here are the files discussed in this milestone + +makeTabs( `router/ts/app/app.component.1.ts, router/ts/app/app.module.1.ts, @@ -562,9 +580,10 @@ h3#router-directives Router Directives crisis-list.component.ts, index.html`) -h2#heroes-feature Milestone #2: The Heroes Feature -.l-main-section +.l-main-section#heroes-feature :marked + ## Milestone #2: The Heroes Feature + We've seen how to navigate using the `RouterLink` directive. Now we'll learn some new tricks such as how to @@ -611,7 +630,8 @@ figure.image-display so its available to all components within our module. Our `Heroes` module is ready for routing. -+makeExample('router/ts/app/heroes/heroes.module.1.ts','', 'app/heroes/heroes.module.ts')(format=".") + ++makeExcerpt('app/heroes/heroes.module.1.ts') :marked When we're done organizing, we have four *Hero Management* files: @@ -645,7 +665,9 @@ figure.image-display We recommend giving each feature area its own route configuration file. Create a new `heroes.routing.ts` in the `heroes` folder like this: -+makeExample('router/ts/app/heroes/heroes.routing.ts','', 'app/heroes/heroes.routing.ts')(format=".") + ++makeExcerpt('app/heroes/heroes.routing.ts') + :marked We use the same techniques we learned for `app.routing.ts`. @@ -661,12 +683,15 @@ figure.image-display our feature-specific routes without modifying our main route configuration. We import our `heroesRouting` token from `heroes.routing.ts` into our `Heroes` module and register the routing. -+makeExample('router/ts/app/heroes/heroes.module.ts', 'heroes-routes', 'app/heroes/heroes.module.ts (Heroes routing)')(format=".") + ++makeExcerpt('app/heroes/heroes.module.ts (heroes routing)', 'heroes-routes') :marked ### Route definition with a parameter The route to `HeroDetailComponent` has a twist. -+makeExample('router/ts/app/heroes/heroes.routing.ts','hero-detail-route')(format=".") + ++makeExcerpt('app/heroes/heroes.routing.ts (excerpt)', 'hero-detail-route', '') + :marked Notice the `:id` token in the path. That creates a slot in the path for a **Route Parameter**. In this case, we're expecting the router to insert the `id` of a hero into that slot. @@ -688,8 +713,10 @@ code-example(format="." language="bash"). An [optional-route-parameter](#optional-route-parameter) might be a better choice if we were passing an *optional* value to `HeroDetailComponent`. -h3#navigate Navigate to hero detail imperatively +a#navigate :marked + ### Navigate to hero detail imperatively + *We won't navigate to the detail component by clicking a link* so we won't be adding a new `RouterLink` anchor tag to the shell. @@ -698,15 +725,21 @@ h3#navigate Navigate to hero detail imperatively We'll adjust the `HeroListComponent` to implement these tasks, beginning with its constructor which acquires the router service and the `HeroService` by dependency injection: -+makeExample('router/ts/app/heroes/hero-list.component.1.ts','ctor', 'app/heroes/hero-list.component.ts (Constructor)')(format=".") + ++makeExcerpt('app/heroes/hero-list.component.1.ts (constructor)', 'ctor') + :marked We make a few changes to the template: -+makeExample('router/ts/app/heroes/hero-list.component.1.ts','template')(format=".") + ++makeExcerpt('app/heroes/hero-list.component.1.ts', 'template', '') + :marked The template defines an `*ngFor` repeater such as [we've seen before](displaying-data.html#ngFor). There's a `(click)` [EventBinding](template-syntax.html#event-binding) to the component's `onSelect` method which we implement as follows: -+makeExample('router/ts/app/heroes/hero-list.component.1.ts','select')(format=".") + ++makeExcerpt('app/heroes/hero-list.component.1.ts', 'select', '') + :marked It calls the router's **`navigate`** method with a **Link Parameters Array**. We can use this same syntax with a `RouterLink` if we want to use it in HTML rather than code. @@ -718,13 +751,19 @@ h3#route-parameters Setting the route parameters in the list view Accordingly, the *link parameters array* has *two* items: the **path** of the destination route and a **route parameter** that specifies the `id` of the selected hero. -+makeExample('router/ts/app/heroes/hero-list.component.1.ts','link-parameters-array')(format=".") + ++makeExcerpt('app/heroes/hero-list.component.1.ts', 'link-parameters-array', '') + :marked The router composes the appropriate two-part destination URL from this array: -code-example(format="." language="bash"). + +code-example(language="bash"). localhost:3000/hero/15 -h3#get-route-parameter Getting the route parameter in the details view + +a#get-route-parameter :marked + ### Getting the route parameter in the details view + How does the target `HeroDetailComponent` learn about that `id`? Certainly not by analyzing the URL! That's the router's job. @@ -735,14 +774,18 @@ 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. -+makeExample('router/ts/app/heroes/hero-detail.component.ts','ctor', 'app/heroes/hero-detail.component.ts (Constructor)')(format=".") + ++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 _subscribe_ to them for the `id` parameter by name and tell the `HeroService` to fetch the hero with that `id`. We'll keep a reference to this `Subscription` so we can tidy things up later. -+makeExample('router/ts/app/heroes/hero-detail.component.ts','ngOnInit')(format=".") + ++makeExcerpt('app/heroes/hero-detail.component.ts', 'ngOnInit', '') + .l-sub-section :marked Angular calls the `ngOnInit` method shortly after creating an instance of the `HeroDetailComponent`. @@ -759,7 +802,8 @@ a#hero-detail-ctor *Failure to do so could create a memory leak.* We unsubscribe from our `Observable` in the `ngOnDestroy` method. -+makeExample('router/ts/app/heroes/hero-detail.component.ts','ngOnDestroy')(format=".") + ++makeExcerpt('app/heroes/hero-detail.component.ts', 'ngOnDestroy', '') .l-sub-section :marked @@ -801,7 +845,9 @@ h4#snapshot Snapshot: the no-observable alternative The router offers a *Snapshot* alternative that gives us the initial value of the route parameters. We don't need to subscribe. We don't have to unsubscribe in `ngOnDestroy`. It's much simpler to write and read: -+makeExample('router/ts/app/heroes/hero-detail.component.2.ts','snapshot')(format=".") + ++makeExcerpt('app/heroes/hero-detail.component.2.ts (excerpt)', 'snapshot', '') + .l-sub-section :marked **Remember:** we only get the _initial_ value of the parameters with this technique. @@ -809,15 +855,18 @@ h4#snapshot Snapshot: the no-observable alternative to this component multiple times in a row. We are leaving the observable `params` strategy in place just in case. -h3#nav-to-list Navigating back to the list component +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 back to the `HeroListComponent`. The router `navigate` method takes the same one-item *link parameters array* that we can bind to a `[routerLink]` directive. It holds the **path to the `HeroListComponent`**: -+makeExample('router/ts/app/heroes/hero-detail.component.1.ts','gotoHeroes')(format=".") + ++makeExcerpt('app/heroes/hero-detail.component.1.ts (excerpt)', 'gotoHeroes', '') h3#merge-hero-routes Import hero module into root NgModule :marked @@ -826,7 +875,7 @@ h3#merge-hero-routes Import hero module into root NgModule Update `app.module.ts` as follows: -+makeExample('router/ts/app/app.module.2.ts','hero-import', 'app.module.ts (Heroes module import)')(format=".") ++makeExcerpt('app/app.module.2.ts (heroes module import)', 'hero-import') :marked We imported the `HeroesModule` and added it to our root NgModule `imports`. @@ -841,7 +890,7 @@ h3#merge-hero-routes Import hero module into root NgModule Since our `Heroes` routes are defined within our submodule, we can also remove our initial `heroes` route from the `app.routing.ts`. -+makeExample('router/ts/app/app.routing.3.ts','', 'app.routing.ts (v.2)')(format=".") ++makeExcerpt('app/app.routing.3.ts (v2)', '') :marked ### Heroes App Wrap-up @@ -883,6 +932,7 @@ h3#merge-hero-routes Import hero module into root NgModule ### The Heroes App code Here are the relevant files for this version of the sample application. + +makeTabs( `router/ts/app/app.component.1.ts, router/ts/app/app.module.2.ts, @@ -901,12 +951,11 @@ h3#merge-hero-routes Import hero module into root NgModule hero.service.ts, heroes.module.ts, heroes.routing.ts`) -:marked - -.l-main-section +.l-main-section#crisis-center-feature :marked ## Milestone #3: The Crisis Center + The *Crisis Center* is a fake view at the moment. Time to make it useful. The new *Crisis Center* begins as a virtual copy of the *Heroes* module. @@ -962,10 +1011,14 @@ h3#merge-hero-routes Import hero module into root NgModule figure.image-display img(src='/resources/images/devguide/router/component-tree.png' alt="Component Tree" ) -h3#child-routing-component Child Routing Component +a#child-routing-component :marked + ### Child Routing Component + Add the following `crisis-center.component.ts` to the `crisis-center` folder: -+makeExample('router/ts/app/crisis-center/crisis-center.component.ts', 'minus-imports', 'crisis-center/crisis-center.component.ts (minus imports)')(format='.') + ++makeExcerpt('app/crisis-center/crisis-center.component.ts (minus imports)', 'minus-imports') + :marked The `CrisisCenterComponent` is much like the `AppComponent` shell. @@ -981,6 +1034,7 @@ h3#child-routing-component Child Routing Component Unlike `AppComponent` (and most other components), it **lacks a selector**. It doesn't need one. We don't *embed* this component in a parent template. We *navigate* to it from the outside, via the router. + .l-sub-section :marked We *can* give it a selector. There's no harm in it. @@ -993,7 +1047,9 @@ h3#child-routing-component Child Routing Component Instead of registering it with the root NgModule's providers — which makes it visible everywhere — we register the `CrisisService` in the `CrisisCenterModule` providers array. -+makeExample('router/ts/app/crisis-center/crisis-center.module.1.ts', 'providers')(format='.') + ++makeExcerpt('app/crisis-center/crisis-center.module.1.ts', 'providers', '') + :marked This limits the scope of the `CrisisService` to the *Crisis Center* routes. No module outside of the *Crisis Center* can access it. @@ -1011,12 +1067,15 @@ h3#child-routing-component Child Routing Component :marked ### Child Route Configuration + The `CrisisCenterComponent` is a *Routing Component* like the `AppComponent`. It has its own `RouterOutlet` and its own child routes. We create a `crisis-center.routing.ts` file as we did the `heroes.routing.ts` file. But this time we define **child routes** *within* the parent `crisis-center` route. -+makeExample('router/ts/app/crisis-center/crisis-center.routing.1.ts', 'routes', 'app/crisis-center/crisis-center.routing.ts (Routes)' )(format='.') + ++makeExcerpt('app/crisis-center/crisis-center.routing.1.ts (Routes)', 'routes') + :marked Notice that the parent `crisis-center` route has a `children` property with an array of two routes. @@ -1039,30 +1098,36 @@ h3#child-routing-component Child Routing Component To write an URL that navigates to the `CrisisDetailComponent`, we'd append the child route path, `/`, followed by the crisis id, yielding something like: -code-example(format=""). +code-example. localhost:3000/crisis-center/2 :marked Here's the complete `crisis-center.routing.ts` with its imports. -+makeExample('router/ts/app/crisis-center/crisis-center.routing.1.ts', '', 'app/crisis-center/crisis-center.routing.ts' )(format='.') + ++makeExcerpt('app/crisis-center/crisis-center.routing.1.ts', '') h3#import-crisis-module Import crisis center module into the root NgModule routes :marked As with the `Heroes` module, we must import the `Crisis Center` module into the root NgModule: -+makeExample('router/ts/app/app.module.3.ts', '', 'app/app.module.ts (Crisis Center Module)' )(format='.') + ++makeExcerpt('app/app.module.3.ts (Crisis Center Module)', '') + :marked We also remove the initial crisis center route from our `app.routing.ts`. Our routes are now being provided by our `HeroesModule` and our `CrisisCenter` submodules. We'll keep our `app.routing.ts` file for general routes which we'll cover later in the chapter. -+makeExample('router/ts/app/app.routing.4.ts', '', 'app/app.routing.ts (v.3)' )(format='.') ++makeExcerpt('app/app.routing.4.ts (v3)', '') a#redirect -h3#redirect Redirecting routes :marked + ### Redirecting routes + When the application launches, the initial URL in the browser bar is something like: -code-example(format=""). + +code-example. localhost:3000 + :marked That doesn't match any of our configured routes which means that our application won't display any component when it's launched. The user must click one of the navigation links to trigger a navigation and display something. @@ -1072,7 +1137,8 @@ code-example(format=""). The preferred solution is to add a `redirect` route that transparently translates from the initial relative URL (`''`) to the desired default path (`/crisis-center`): -+makeExample('router/ts/app/crisis-center/crisis-center.routing.2.ts', 'redirect', 'app/crisis-center/crisis-center.routing.ts (redirect route)' )(format='.') + ++makeExcerpt('app/crisis-center/crisis-center.routing.2.ts' , 'redirect', '') :marked A redirect route requires a `pathMatch` property to tell the router how to match a URL to the path of a route. @@ -1102,7 +1168,8 @@ code-example(format=""). :marked The updated route definitions look like this: -+makeExample('router/ts/app/crisis-center/crisis-center.routing.2.ts', 'routes', 'app/crisis-center/crisis-center.routing.ts (Routes v.2)' )(format='.') + ++makeExcerpt('app/crisis-center/crisis-center.routing.2.ts (routes v2)' , 'routes') .l-main-section h2#guards Route Guards @@ -1153,15 +1220,16 @@ h2#guards Route Guards Let's look at some examples. -.l-main-section -// :marked - +.l-main-section#lifecycle-hooks +:marked ## Router Lifecycle Hooks TODO: Pausing activation -h3#can-activate-guard CanActivate: requiring authentication +a#can-activate-guard :marked + ### *CanActivate*: requiring authentication + Applications often restrict access to a feature area based on who the user is. We could permit access only to authenticated users or to users with a specific role. We might block or limit access until the user's account is activated. @@ -1173,13 +1241,17 @@ h3#can-activate-guard CanActivate: requiring authentication We intend to extend the Crisis Center with some new *administrative* features. Those features aren't defined yet. So we add the following placeholder component. -+makeExample('router/ts/app/crisis-center/crisis-admin.component.1.ts', '', 'crisis-admin.component.ts')(format=".") ++makeExcerpt('app/crisis-center/crisis-admin.component.1.ts') + :marked Next, we add a child route to the `crisis-center.routes` with the path, `/admin`. -+makeExample('router/ts/app/crisis-center/crisis-center.routing.3.ts', 'admin-route-no-guard', 'crisis-center.routing.ts (admin route)')(format=".") + ++makeExcerpt('app/crisis-center/crisis-center.routing.3.ts (admin route)', 'admin-route-no-guard') + :marked And we add a link to the `AppComponent` shell that users can click to get to this feature. -+makeExample('router/ts/app/app.component.4.ts', 'template', 'app/app.component.ts (template)')(format=".") + ++makeExcerpt('app/app.component.4.ts', 'template') .l-sub-section :marked @@ -1202,19 +1274,26 @@ h3#can-activate-guard CanActivate: requiring authentication At the moment we're interested in seeing how guards work so our first version does nothing useful. It simply logs to console and `returns` true immediately, allowing navigation to proceed: -+makeExample('router/ts/app/auth-guard.service.1.ts', '', 'app/auth-guard.service.ts')(format=".") + ++makeExcerpt('app/auth-guard.service.1.ts') + :marked Next we open `crisis-center.routing.ts `, import the `AuthGuard` class, and update the admin route with a `CanActivate` guard property that references it: -+makeExample('router/ts/app/crisis-center/crisis-center.routing.ts', 'admin-route', 'crisis-center.routing.ts (guarded admin route)')(format=".") - Our admin feature is now protected by the guard, albeit protected poorly. + ++makeExcerpt('app/crisis-center/crisis-center.routing.ts (guarded admin route)', 'admin-route') + :marked + Our admin feature is now protected by the guard, albeit protected poorly. + #### Teach *AuthGuard* to authenticate Let's make our `AuthGuard` at least pretend to authenticate. The `AuthGuard` should call an application service that can login a user and retain information about the current user. Here's a demo `AuthService`: -+makeExample('router/ts/app/auth.service.ts', '', 'app/auth.service.ts')(format=".") + ++makeExcerpt('app/auth.service.ts') + :marked Although it doesn't actually log in, it has what we need for this discussion. It has an `isLoggedIn` flag to tell us whether the user is authenticated. @@ -1222,7 +1301,9 @@ h3#can-activate-guard CanActivate: requiring authentication The `redirectUrl` property will store our attempted URL so we can navigate to it after authenticating. Let's revise our `AuthGuard` to call it. -+makeExample('router/ts/app/auth-guard.service.2.ts', '', 'app/auth-guard.service.ts (v.2)')(format=".") + ++makeExcerpt('app/auth-guard.service.2.ts (v2)', '') + :marked Notice that we *inject* the `AuthService` and the `Router` in the constructor. We haven't provided the `AuthService` yet but it's good to know that we can inject helpful services into our routing guards. @@ -1295,7 +1376,9 @@ h3#can-deactivate-guard CanDeactivate: handling unsaved changes We discard the changes if the user presses he *Cancel* button. Both buttons navigate back to the crisis list after save or cancel. -+makeExample('router/ts/app/crisis-center/crisis-detail.component.1.ts', 'cancel-save', 'crisis-detail.component.ts (excerpt)')(format=".") + ++makeExcerpt('app/crisis-center/crisis-detail.component.1.ts (excerpt)', 'cancel-save') + :marked What if the user tries to navigate away without saving or canceling? The user could push the browser back button or click the heroes link. @@ -1318,24 +1401,27 @@ h3#can-deactivate-guard CanDeactivate: handling unsaved changes *resolves* when the user eventually decides what to do: either to discard changes and navigate away (`true`) or to preserve the pending changes and stay in the crisis editor (`false`). - +a#CanDeactivate :marked We create a `Guard` that will check for the presence of a `canDeactivate` function in our component, in this case being `CrisisDetailComponent`. We don't need to know the details of how our `CrisisDetailComponent` confirms deactivation. This makes our guard reusable, which is an easy win for us. -+makeExample('router/ts/app/can-deactivate-guard.service.ts', '', 'can-deactivate-guard.service.ts') + ++makeExample('app/can-deactivate-guard.service.ts') :marked Alternatively, We could make a component-specific `CanDeactivate` guard for our `CrisisDetailComponent`. The `canDeactivate` method provides us with the current instance of our `component`, the current `ActivatedRoute` and `RouterStateSnapshot` in case we needed to access some external information. This would be useful if we only wanted to use this guard for this component and needed to ask the component's properties in or to confirm whether the router should allow navigation away from it. -+makeExample('router/ts/app/can-deactivate-guard.service.1.ts', '', 'can-deactivate-guard.service.ts (component-specific)') + ++makeExcerpt('app/can-deactivate-guard.service.1.ts (component-specific)', '') :marked Looking back at our `CrisisDetailComponent`, we have implemented our confirmation workflow for unsaved changes. -+makeExample('router/ts/app/crisis-center/crisis-detail.component.1.ts', 'cancel-save-only', 'crisis-detail.component.ts (excerpt)') ++makeExcerpt('app/crisis-center/crisis-detail.component.1.ts (excerpt)', 'cancel-save-only') + :marked Notice that the `canDeactivate` method *can* return synchronously; it returns `true` immediately if there is no crisis or there are no pending changes. @@ -1344,11 +1430,13 @@ h3#can-deactivate-guard CanDeactivate: handling unsaved changes :marked We add the `Guard` to our crisis detail route in `crisis-center.routing.ts` using the `canDeactivate` array. -+makeExample('router/ts/app/crisis-center/crisis-center.routing.4.ts', '', 'crisis-center.routing.ts') + ++makeExample('app/crisis-center/crisis-center.routing.4.ts', '') :marked We also need to add the `Guard` to our main `appRoutingProviders` so the `Router` can inject it during the navigation process. -+makeExample('router/ts/app/app.routing.5.ts', '', 'app.routing.ts') + ++makeExample('app/app.routing.5.ts', '', '') :marked Now we have given our user a safeguard against unsaved changes. @@ -1387,7 +1475,7 @@ h3#resolve-guard Resolve: pre-fetching component data Let's create our `crisis-detail-resolve.service.ts` file within our `Crisis Center` feature area. -+makeExample('router/ts/app/crisis-center/crisis-detail-resolve.service.ts', '', 'crisis-detail-resolve.service.ts') ++makeExample('app/crisis-center/crisis-detail-resolve.service.ts', '') :marked We'll take the relevant parts of the `ngOnInit` lifecycle hook in our `CrisisDetailComponent` and moved them into our `CrisisDetailResolve` guard. @@ -1401,12 +1489,12 @@ h3#resolve-guard Resolve: pre-fetching component data Now that our guard is ready, we'll import it in our `crisis-center.routing.ts` and use the `resolve` object in our route configuration. -+makeExample('router/ts/app/crisis-center/crisis-center.routing.5.ts', 'crisis-detail-resolve', 'crisis-center.routing.ts (resolve)') ++makeExcerpt('app/crisis-center/crisis-center.routing.5.ts (resolve)', 'crisis-detail-resolve') :marked We'll add the `CrisisDetailResolve` service to our crisis center module's `providers`, so its available to the `Router` during the navigation process. -+makeExample('router/ts/app/crisis-center/crisis-center.module.ts', 'crisis-detail-resolve', 'crisis-center.module.ts (crisis detail resolve provider)') ++makeExcerpt('app/crisis-center/crisis-center.module.ts (crisis detail resolve provider)', 'crisis-detail-resolve') :marked Now that we've added our `Resolve` guard to fetch data before the route loads, we no longer need to do this once we get into our `CrisisDetailComponent`. @@ -1414,7 +1502,7 @@ h3#resolve-guard Resolve: pre-fetching component data Once activated, all we need to do is set our local `crisis` and `editName` properties from our resolved `Crisis` information. We no longer need to subscribe and unsubscribe to the `ActivatedRoute` params to fetch the `Crisis` because it is being provided synchronously at the time the route component is activated. -+makeExample('router/ts/app/crisis-center/crisis-detail.component.ts', 'crisis-detail-resolve', 'crisis-detail.component.ts (ngOnInit v.2)') ++makeExcerpt('app/crisis-center/crisis-detail.component.ts (ngOnInit v2)', 'crisis-detail-resolve') :marked **Two critical points** @@ -1455,8 +1543,7 @@ h3#resolve-guard Resolve: pre-fetching component data `) - -.l-main-section +.l-main-section#optional-route-parameters :marked ## Milestone #4: Route Parameters @@ -1500,18 +1587,24 @@ figure.image-display ### Route parameter + When navigating to the `HeroDetailComponent` we specified the `id` of the hero-to-edit in the *route parameter* and made it the second item of the [*link parameters array*](#link-parameters-array). -+makeExample('router/ts/app/heroes/hero-list.component.1.ts','link-parameters-array')(format=".") ++makeExcerpt('app/heroes/hero-list.component.1.ts', 'link-parameters-array', '') + :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`: -+makeExample('router/ts/app/heroes/heroes.routing.ts','hero-detail-route')(format=".") + ++makeExcerpt('app/heroes/heroes.routing.ts', 'hero-detail-route', '') + :marked When the user clicks the back button, the `HeroDetailComponent` constructs another *link parameters array* which it uses to navigate back to the `HeroListComponent`. -+makeExample('router/ts/app/heroes/hero-detail.component.1.ts','gotoHeroes')(format=".") + ++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`. @@ -1521,7 +1614,9 @@ figure.image-display We do that with an object that contains our optional `id` parameter. We also defined a junk parameter (`foo`) that the `HeroListComponent` should ignore. Here's the revised navigation statement: -+makeExample('router/ts/app/heroes/hero-detail.component.ts','gotoHeroes-navigate')(format=".") + ++makeExcerpt('app/heroes/hero-detail.component.ts', 'gotoHeroes-navigate', '') + :marked The application still works. Clicking "back" returns to the hero list view. @@ -1532,15 +1627,18 @@ figure.image-display When running in plunker, pop out the preview window by clicking the blue 'X' button in the upper right corner. :marked It should look something like this, depending on where you run it: -code-example(format="." language="bash"). + +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. -:marked + The optional route parameters are not separated by "?" and "&". They are **separated by semicolons (;)** This is *matrix URL* notation — something we may not have seen before. + .l-sub-section :marked *Matrix URL* notation is an idea first floated @@ -1575,23 +1673,31 @@ code-example(format="." language="bash"). This time we'll be navigating in the opposite direction, from the `HeroDetailComponent` to the `HeroListComponent`. First we extend the router import statement to include the `ActivatedRoute` service symbol; -+makeExample('router/ts/app/heroes/hero-list.component.ts','import-router', 'hero-list.component.ts (import)')(format=".") + ++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`: -+makeExample('router/ts/app/heroes/hero-list.component.ts','ctor', 'hero-list.component.ts (constructor)')(format=".") + ++makeExcerpt('app/heroes/hero-list.component.ts (constructor)', 'ctor') + .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. :marked We add an `isSelected` method that returns true when a hero's id matches the selected id. -+makeExample('router/ts/app/heroes/hero-list.component.ts','isSelected', 'hero-list.component.ts (constructor)')(format=".") + ++makeExcerpt('app/heroes/hero-list.component.ts', 'isSelected') + :marked 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: -+makeExample('router/ts/app/heroes/hero-list.component.ts','template', 'hero-list.component.ts (template)')(format=".") + ++makeExcerpt('app/heroes/hero-list.component.ts', 'template') + :marked When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected: figure.image-display @@ -1599,11 +1705,11 @@ figure.image-display :marked The optional `foo` route parameter is harmless and continues to be ignored. - - +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. @@ -1616,7 +1722,8 @@ figure.image-display 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. -+makeExample('router/ts/app/auth-guard.service.ts','', 'auth-guard.service.ts (v.3)') + ++makeExcerpt('app/auth-guard.service.ts (v3)', '') :marked We can also **preserve** query parameters and fragments across navigations without having to re-provide them @@ -1624,13 +1731,14 @@ figure.image-display and provide the `preserveQueryParams` and `preserveFragment` to pass along the current query parameters and fragment to the next route. -+makeExample('router/ts/app/login.component.ts','preserve', 'login.component.ts (preserved)')(format=".") ++makeExcerpt('app/login.component.ts', 'preserve') :marked Since we'll be navigating to our *Crisis Admin* route after logging in, we'll update it to handle our query parameters and fragment. -+makeExample('router/ts/app/crisis-center/crisis-admin.component.ts','', 'crisis-admin.component.ts (v.2)') ++makeExcerpt('app/crisis-center/crisis-admin.component.ts (v2)', '') + :marked *Query Parameters* and *Fragments* are also available through the `ActivatedRoute` service available to route components. Just like our *route parameters*, query parameters and fragments are provided as an `Observable`. @@ -1696,7 +1804,7 @@ figure.image-display out our `Crisis Center` 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 `CrisisCenter` NgModule. If we look in our `crisis-center.module` file, we can see it matches name of our exported NgModule class. -+makeExample('router/ts/app/crisis-center/crisis-center.module.ts', 'crisis-center-module-export', 'crisis-center.module.ts (export)') ++makeExcerpt('app/crisis-center/crisis-center.module.ts (export)', 'crisis-center-module-export') :marked The `loadChildren` property is used by the `Router` to map to our bundle we want to lazy-load, in this case being the `CrisisCenterModule`. @@ -1714,13 +1822,13 @@ figure.image-display to break our `CrisisCenterModule` into a completely separate module. In our `app.module.ts`, we'll remove our `CrisisCenterModule` from the `imports` array since we'll be loading it on-demand an we'll remove the imported `CrisisCenterModule`. -+makeExample('router/ts/app/app.module.ts', '', 'app.module.ts (final)') ++makeExcerpt('app/app.module.ts (final)', '') :marked If our initial redirect went to `/heroes` instead of going to `/crisis-center`, the `CrisisCenterModule` would not be loaded until the user visited a `Crisis Center` route. We'll update our redirect in our `app.routing.ts` to make this change. -+makeExample('router/ts/app/app.routing.6.ts', 'heroes-redirect', 'app.routing.ts (heroes redirect)') ++makeExcerpt('app/app.routing.6.ts (heroes redirect)', 'heroes-redirect') .l-main-section @@ -1739,10 +1847,10 @@ figure.image-display The appendix material isn't essential. Continued reading is for the curious. -.l-main-section - +.l-main-section#link-parameters-array :marked ## Appendix: Link Parameters Array + 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: @@ -1750,19 +1858,27 @@ figure.image-display * required and optional route parameters that go into the route URL We can bind the `RouterLink` directive to such an array like this: -+makeExample('router/ts/app/app.component.3.ts', 'h-anchor')(format=".") + ++makeExcerpt('app/app.component.3.ts', 'h-anchor', '') + :marked We've written a two element array when specifying a route parameter like this -+makeExample('router/ts/app/heroes/hero-list.component.1.ts', 'nav-to-detail')(format=".") + ++makeExcerpt('app/heroes/hero-list.component.1.ts', 'nav-to-detail', '') + :marked We can provide optional route parameters in an object like this: -+makeExample('router/ts/app/app.component.3.ts', 'cc-query-params')(format=".") + ++makeExcerpt('app/app.component.3.ts', 'cc-query-params', '') + :marked These three examples cover our needs for an app with one level routing. The moment we add a child router, such as the *Crisis Center*, we create new link array possibilities. Recall that we specified a default child route for *Crisis Center* so this simple `RouterLink` is fine. -+makeExample('router/ts/app/app.component.3.ts', 'cc-anchor-w-default')(format=".") + ++makeExcerpt('app/app.component.3.ts', 'cc-anchor-w-default', '') + :marked Let's parse it out. * The first item in the array identifies the parent route ('/crisis-center'). @@ -1782,17 +1898,20 @@ figure.image-display * We add `id` of the *Dragon Crisis* as the second item in the array (`1`) It looks like this! -+makeExample('router/ts/app/app.component.3.ts', 'Dragon-anchor')(format=".") + ++makeExcerpt('app/app.component.3.ts', 'Dragon-anchor', '') + :marked If we wanted to, we could redefine our `AppComponent` template with *Crisis Center* routes exclusively: -+makeExample('router/ts/app/app.component.3.ts', 'template')(format=".") + ++makeExcerpt('app/app.component.3.ts', 'template', '') + :marked In sum, we can write applications with one, two or more levels of routing. The link parameters array affords the flexibility to represent any routing depth and any legal sequence of route paths, (required) router parameters and (optional) route parameter objects. - -.l-main-section +.l-main-section#onInit :marked ## Appendix: Why use an *ngOnInit* method @@ -1890,7 +2009,9 @@ code-example(format=".", language="bash"). The preferred way to configure the strategy is to add a [<base href> element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag in the `` of the `index.html`. -+makeExample('router/ts/index.1.html','base-href')(format=".") + ++makeExcerpt('index.1.html', 'base-href', '') + :marked Without that tag, the browser may not be able to load resources (images, css, scripts) when "deep linking" into the app. @@ -1914,4 +2035,5 @@ code-example(format=".", language="bash"). We can go old-school with the `HashLocationStrategy` by providing the `useHash: true` in an object as the second argument of the `RouterModule.forRoot` in our root NgModule. -+makeExample('router/ts/app/app.module.4.ts','', 'app.module.ts (hash URL strategy)') + ++makeExcerpt('app/app.module.4.ts (hash URL strategy)', '') From dfd46af6049045fd217a520033406fd1be947fd7 Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Fri, 12 Aug 2016 11:21:16 -0700 Subject: [PATCH 011/247] docs(toh-6): post-RC5 Dart resync and TS fixes (#2095) * toh-6: trim spaces from cache file to simplify diff * toh-6: copy latest over cache before editing latest * docs(toh-6): post-RC5 Dart resync and TS fixes Contributes to #2077. TS-side changes include: - Merged three versions of `app/app.module{,1,2}.ts` into a single file and used docregions instead. - Misnamed files: - `rxjs-operators.ts` -> `rxjs-extensions.ts` - `hero-search.service.html` -> `hero-search.component.html` - Fixed BAD FILENAME error. Lint reports no errors and toh-6 e2e tests pass. --- .../toh-6/dart/lib/dashboard_component.dart | 3 +- .../docs/_examples/toh-6/dart/web/main.dart | 5 +- .../_examples/toh-6/ts/app/app.module.1.ts | 44 --------- .../_examples/toh-6/ts/app/app.module.2.ts | 44 --------- .../docs/_examples/toh-6/ts/app/app.module.ts | 22 ++++- public/docs/dart/latest/tutorial/toh-pt6.jade | 32 +++--- public/docs/ts/_cache/tutorial/toh-pt6.jade | 98 +++++++++---------- public/docs/ts/latest/tutorial/toh-pt6.jade | 44 +++++---- 8 files changed, 110 insertions(+), 182 deletions(-) delete mode 100644 public/docs/_examples/toh-6/ts/app/app.module.1.ts delete mode 100644 public/docs/_examples/toh-6/ts/app/app.module.2.ts diff --git a/public/docs/_examples/toh-6/dart/lib/dashboard_component.dart b/public/docs/_examples/toh-6/dart/lib/dashboard_component.dart index da965c301c..d23b7f543d 100644 --- a/public/docs/_examples/toh-6/dart/lib/dashboard_component.dart +++ b/public/docs/_examples/toh-6/dart/lib/dashboard_component.dart @@ -1,4 +1,4 @@ -// #docregion , search +// #docregion import 'dart:async'; import 'package:angular2/core.dart'; @@ -6,6 +6,7 @@ import 'package:angular2/router.dart'; import 'hero.dart'; import 'hero_service.dart'; +// #docregion search import 'hero_search_component.dart'; @Component( diff --git a/public/docs/_examples/toh-6/dart/web/main.dart b/public/docs/_examples/toh-6/dart/web/main.dart index ff344d1a54..7e41d5d227 100644 --- a/public/docs/_examples/toh-6/dart/web/main.dart +++ b/public/docs/_examples/toh-6/dart/web/main.dart @@ -1,6 +1,5 @@ // #docplaster -// #docregion final -// #docregion v1 +// #docregion , v1, v2 import 'package:angular2/core.dart'; import 'package:angular2/platform/browser.dart'; import 'package:angular2_tour_of_heroes/app_component.dart'; @@ -15,7 +14,7 @@ void main() { // [provide(Client, useFactory: () => new BrowserClient(), deps: [])] ); } -// #enddocregion final +// #enddocregion v2, /* // #docregion v1 import 'package:http/browser_client.dart'; diff --git a/public/docs/_examples/toh-6/ts/app/app.module.1.ts b/public/docs/_examples/toh-6/ts/app/app.module.1.ts deleted file mode 100644 index 6924d5a390..0000000000 --- a/public/docs/_examples/toh-6/ts/app/app.module.1.ts +++ /dev/null @@ -1,44 +0,0 @@ -// #docplaster -// #docregion -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; - -// Imports for loading & configuring the in-memory web api -import { HttpModule, XHRBackend } from '@angular/http'; - -import { InMemoryBackendService, SEED_DATA } from 'angular2-in-memory-web-api'; -import { InMemoryDataService } from './in-memory-data.service'; - -import { AppComponent } from './app.component'; -import { routing } from './app.routing'; - -import { HeroesComponent } from './heroes.component'; -import { DashboardComponent } from './dashboard.component'; -import { HeroDetailComponent } from './hero-detail.component'; - -import { HeroService } from './hero.service'; - -@NgModule({ - imports: [ - BrowserModule, - FormsModule, - routing, - HttpModule - ], - declarations: [ - AppComponent, - HeroesComponent, - DashboardComponent, - HeroDetailComponent - ], - providers: [ - HeroService, - { provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server - { provide: SEED_DATA, useClass: InMemoryDataService } // in-mem server data - ], - bootstrap: [ AppComponent ] -}) -export class AppModule { -} -// #enddocregion final diff --git a/public/docs/_examples/toh-6/ts/app/app.module.2.ts b/public/docs/_examples/toh-6/ts/app/app.module.2.ts deleted file mode 100644 index 2ec598cd0b..0000000000 --- a/public/docs/_examples/toh-6/ts/app/app.module.2.ts +++ /dev/null @@ -1,44 +0,0 @@ -// #docplaster -// #docregion -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; -import { HttpModule } from '@angular/http'; - -import { AppComponent } from './app.component'; -import { routing } from './app.routing'; - -import { HeroesComponent } from './heroes.component'; -import { DashboardComponent } from './dashboard.component'; -import { HeroDetailComponent } from './hero-detail.component'; -// #docregion hero-search-declaration -import { HeroSearchComponent } from './hero-search.component'; -// #enddocregion hero-search-declaration - -import { HeroService } from './hero.service'; - -@NgModule({ - imports: [ - BrowserModule, - FormsModule, - routing, - HttpModule - ], -// #docregion hero-search-declaration - - declarations: [ - AppComponent, - HeroesComponent, - DashboardComponent, - HeroDetailComponent, - HeroSearchComponent - ], -// #enddocregion hero-search-declaration - providers: [ - HeroService - ], - bootstrap: [ AppComponent ] -}) -export class AppModule { -} -// #enddocregion diff --git a/public/docs/_examples/toh-6/ts/app/app.module.ts b/public/docs/_examples/toh-6/ts/app/app.module.ts index 0beff178e0..032ef28d8f 100644 --- a/public/docs/_examples/toh-6/ts/app/app.module.ts +++ b/public/docs/_examples/toh-6/ts/app/app.module.ts @@ -1,24 +1,31 @@ -// #docregion +// #docplaster +// #docregion , v1, v2 import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; +// #enddocregion v1 // Imports for loading & configuring the in-memory web api -import { HttpModule, XHRBackend } from '@angular/http'; +import { XHRBackend } from '@angular/http'; import { InMemoryBackendService, SEED_DATA } from 'angular2-in-memory-web-api'; import { InMemoryDataService } from './in-memory-data.service'; +// #docregion v1 import { AppComponent } from './app.component'; import { routing } from './app.routing'; import { HeroesComponent } from './heroes.component'; import { DashboardComponent } from './dashboard.component'; import { HeroDetailComponent } from './hero-detail.component'; +import { HeroService } from './hero.service'; +// #enddocregion v1, v2 +// #docregion search import { HeroSearchComponent } from './hero-search.component'; +// #docregion v1, v2 -import { HeroService } from './hero.service'; - +// #enddocregion search @NgModule({ imports: [ BrowserModule, @@ -26,20 +33,25 @@ import { HeroService } from './hero.service'; routing, HttpModule ], + // #docregion search declarations: [ AppComponent, HeroesComponent, DashboardComponent, HeroDetailComponent, + // #enddocregion v1, v2 HeroSearchComponent + // #docregion v1, v2 ], + // #enddocregion search providers: [ HeroService, + // #enddocregion v1 { provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server { provide: SEED_DATA, useClass: InMemoryDataService } // in-mem server data + // #docregion v1 ], bootstrap: [ AppComponent ] }) export class AppModule { } -// #enddocregion diff --git a/public/docs/dart/latest/tutorial/toh-pt6.jade b/public/docs/dart/latest/tutorial/toh-pt6.jade index 888bdb78bf..0ca2c931ed 100644 --- a/public/docs/dart/latest/tutorial/toh-pt6.jade +++ b/public/docs/dart/latest/tutorial/toh-pt6.jade @@ -6,7 +6,7 @@ block includes - var _Angular_Http = 'Dart BrowserClient' - var _httpUrl = 'https://pub.dartlang.org/packages/http' - var _Angular_http_library = 'Dart http package' - - var _HTTP_PROVIDERS = 'BrowserClient' + - var _HttpModule = 'BrowserClient' - var _JSON_stringify = 'JSON.encode' block start-server-and-watch @@ -17,15 +17,15 @@ block start-server-and-watch code-example(language="bash"). pub serve - + block http-library :marked - We'll be using the !{_Angular_http_library}'s + We'll be using the !{_Angular_http_library}'s `BrowserClient` class to communicate with a server. ### Pubspec updates - - We need to add package dependencies for the + + We need to add package dependencies for the `stream_transformers` and !{_Angular_http_library}s. We also need to add a `resolved_identifiers` entry, to inform the [angular2 @@ -45,10 +45,21 @@ block http-providers :marked Before our app can use `#{_Http}`, we have to register it as a service provider. + We should be able to access `!{_Http}` services from anywhere in the application. + So we register it in the `bootstrap` call where we + launch the application and its root `AppComponent`. + + +makeExcerpt('app/main.ts','v1') + + :marked + Notice that we supply `!{_HttpModule}` in a list, as the second parameter to + the `bootstrap` method. This has the same effect as the `providers` list in + `@Component` annotation. + block backend :marked We want to replace `BrowserClient`, the service that talks to the remote server, - with the in-memory web API service. + with the in-memory web API service. Our in-memory web API service, shown below, is implemented using the `http` library `MockClient` class. All `http` client implementations share a common `Client` interface, so @@ -77,7 +88,7 @@ block hero-detail-comp-updates :marked ### Edit in the *HeroDetailComponent* - We already have `HeroDetailComponent` for viewing details about a specific hero. + We already have `HeroDetailComponent` for viewing details about a specific hero. Supporting edit functionality is a natural extension of the detail view, so we are able to reuse `HeroDetailComponent` with a few tweaks. @@ -87,9 +98,6 @@ block hero-detail-comp-save-and-goback block add-new-hero-via-detail-comp //- N/A -block heroes-comp-directives - //- N/A - block heroes-comp-add //- N/A @@ -194,10 +202,10 @@ block file-summary lib/hero_search_component.dart, lib/hero_search_component.html, lib/hero_search_service.dart`) - + +makeTabs( `toh-6/dart/pubspec.yaml, toh-6/dart/web/main.dart`, - `,final`, + null, `pubspec.yaml, web/main.dart`) diff --git a/public/docs/ts/_cache/tutorial/toh-pt6.jade b/public/docs/ts/_cache/tutorial/toh-pt6.jade index c93ec199ca..1843772aab 100644 --- a/public/docs/ts/_cache/tutorial/toh-pt6.jade +++ b/public/docs/ts/_cache/tutorial/toh-pt6.jade @@ -5,7 +5,7 @@ block includes - var _Http = 'Http'; // Angular `Http` library name. - var _Angular_Http = 'Angular Http' - var _Angular_http_library = 'Angular HTTP library' - - var _HTTP_PROVIDERS = 'HTTP_PROVIDERS' + - var _HttpModule = 'HttpModule' - var _JSON_stringify = 'JSON.stringify' :marked @@ -53,25 +53,24 @@ block http-library block http-providers :marked Our app will depend upon the Angular `http` service which itself depends upon other supporting services. - The `HTTP_PROVIDERS` array from `@angular/http` library holds providers for the complete set of http services. + The `HttpModule` from `@angular/http` library holds providers for the complete set of `http` services. -:marked - We should be able to access `!{_Http}` services from anywhere in the application. - So we register them in the `bootstrap` call of main.ts where we - launch the application and its root `AppComponent`. + We should be able to access `http` services from anywhere in the application. + So we register them in the `imports` array of `app.module.ts` where we + bootstrap the application and its root `AppComponent`. -+makeExcerpt('app/main.ts','v1') + +makeExcerpt('app/app.module.ts (v1)') -:marked - Notice that we supply `!{_HTTP_PROVIDERS}` in !{_an} !{_array} as the second parameter to the `bootstrap` method. - This has the same effect as the `providers` !{_array} in `@Component` !{_decorator}. + :marked + Notice that we supply `!{_HttpModule}` as part of the *imports* !{_array} in root NgModule `AppModule`. .l-main-section :marked ## Simulating the web API - We generally recommend registering application-wide services in the root `AppComponent` *providers*. - Here we're registering in `main` for a special reason. + We recommend registering application-wide services in the root + `!{_AppModuleVsAppComp}` *providers*. Here we're + registering in `main` for a special reason. Our application is in the early stages of development and far from ready for production. We don't even have a web server that can handle requests for heroes. @@ -79,12 +78,13 @@ block http-providers We're going to *trick* the HTTP client into fetching and saving data from a mock service, the *in-memory web API*. + The application itself doesn't need to know and + shouldn't know about this. So we'll slip the in-memory web API into the + configuration *above* the `AppComponent`. - The application itself doesn't need to know and shouldn't know about this. - So we'll slip the in-memory web API into the configuration *above* the `AppComponent`. + Here is a version of !{_appModuleTsVsMainTs} that performs this trick: - Here is a version of `main` that performs this trick -+makeExcerpt('app/main.ts', 'final') ++makeExcerpt(_appModuleTsVsMainTs, 'v2') block backend :marked @@ -133,7 +133,7 @@ block get-heroes-details *Observables* are a powerful way to manage asynchronous data flows. We'll learn about [Observables](#observables) later in this chapter. - For *now* we get back on familiar ground by immediately by + For *now* we get back on familiar ground by immediately by converting that `Observable` to a `Promise` using the `toPromise` operator. +makeExcerpt('app/hero.service.ts', 'to-promise', '') :marked @@ -326,19 +326,6 @@ block add-new-hero-via-detail-comp Now let's fix-up the `HeroesComponent` to support the *add* and *delete* actions used in the template. Let's start with *add*. -block heroes-comp-directives - :marked - We're using the `HeroDetailComponent` to capture the new hero information. - We have to tell Angular about that by importing the `HeroDetailComponent` and referencing it in the component metadata `directives` array. - +makeExcerpt('app/heroes.component.ts (HeroDetailComponent)', 'hero-detail-component') - .l-sub-section - :marked - These are the same lines that we removed in the previous [Routing](toh-pt5.html) chapter. - We didn't know at the time that we'd need the *HeroDetailComponent* again. So we tidied up. - - Now we *must* put these lines back. If we don't, Angular will ignore the `` - tag and pushing the *Add New Hero* button will have no visible effect. -:marked Implement the click handler for the *Add New Hero* button. +makeExcerpt('app/heroes.component.ts', 'addHero') @@ -372,7 +359,7 @@ block observables-section-intro Each `Http` method returns an `Observable` of HTTP `Response` objects. Our `HeroService` converts that `Observable` into a `Promise` and returns the promise to the caller. - In this section we learn to return the `Observable` directly and discuss when and why that might be + In this section we learn to return the `Observable` directly and discuss when and why that might be a good thing to do. ### Background @@ -385,15 +372,15 @@ block observables-section-intro Recall that our `HeroService` quickly chained the `toPromise` operator to the `Observable` result of `http.get`. That operator converted the `Observable` into a `Promise` and we passed that promise back to the caller. - Converting to a promise is often a good choice. We typically ask `http` to fetch a single chunk of data. + Converting to a promise is often a good choice. We typically ask `http` to fetch a single chunk of data. When we receive the data, we're done. - A single result in the form of a promise is easy for the calling component to consume + A single result in the form of a promise is easy for the calling component to consume and it helps that promises are widely understood by JavaScript programmers. :marked - But requests aren't always "one and done". We may start one request, + But requests aren't always "one and done". We may start one request, then cancel it, and make a different request before the server has responded to the first request. - Such a _request-cancel-new-request_ sequence is difficult to implement with *!{_Promise}s*. + Such a _request-cancel-new-request_ sequence is difficult to implement with *!{_Promise}s*. It's easy with *!{_Observable}s* as we'll see. ### Search-by-name @@ -407,12 +394,12 @@ block observables-section-intro :marked The `!{_priv}http.get()` call in `HeroSearchService` is similar to the one in the `HeroService`, although the URL now has a query string. - Another notable difference: we no longer call `toPromise`, + Another notable difference: we no longer call `toPromise`, we simply return the *observable* instead. ### HeroSearchComponent - Let's create a new `HeroSearchComponent` that calls this new `HeroSearchService`. + Let's create a new `HeroSearchComponent` that calls this new `HeroSearchService`. The component template is simple — just a text box and a list of matching search results. @@ -435,7 +422,7 @@ block observables-section-intro :marked #### Search terms - + Let's focus on the `!{_priv}searchTerms`: +makeExcerpt('app/hero-search.component.ts', 'searchTerms', '') @@ -466,7 +453,7 @@ block observable-transformers Fortunately, we can chain `Observable` operators to the string `Observable` that reduce the request flow. We'll make fewer calls to the `HeroSearchService` and still get timely results. Here's how: - * `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds + * `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds before passing along the latest string. We'll never make requests more frequently than 300ms. * `distinctUntilChanged` ensures that we only send a request if the filter text changed. @@ -481,21 +468,21 @@ block observable-transformers (formerly known as "flatMapLatest") is very clever. Every qualifying key event can trigger an http call. - Even with a 300ms pause between requests, we could have multiple http requests in flight + Even with a 300ms pause between requests, we could have multiple http requests in flight and they may not return in the order sent. `switchMap` preserves the original request order while returning - only the observable from the most recent http call. + only the observable from the most recent http call. Results from prior calls are canceled and discarded. - We also short-circuit the http call and return an observable containing an empty array + We also short-circuit the http call and return an observable containing an empty array if the search text is empty. Note that _canceling_ the `HeroSearchService` observable won't actually abort a pending http request until the service supports that feature, a topic for another day. We are content for now to discard unwanted results. :marked - * `catch` intercepts a failed observable. + * `catch` intercepts a failed observable. Our simple example prints the error to the console; a real life application should do better. Then we return an observable containing an empty array to clear the search result. @@ -510,7 +497,7 @@ block observable-transformers :marked Many authorities say we should do just that. :marked - We take a different approach in this example. + We take a different approach in this example. We combine all of the RxJS `Observable` extensions that _our entire app_ requires into a single RxJS imports file. +makeExample('app/rxjs-extensions.ts') @@ -527,10 +514,12 @@ block observable-transformers +makeExample('app/dashboard.component.html') +- var _declarations = _docsFor == 'dart' ? 'directives' : 'declarations' +- var declFile = _docsFor == 'dart' ? 'app/dashboard.component.ts' : 'app/app.module.ts' :marked - And finally, we import the `HeroSearchComponent` and add it to the `directives` !{_array}. + And finally, we import the `HeroSearchComponent` and add it to the `!{_declarations}` !{_array}: -+makeExcerpt('app/dashboard.component.ts', 'search') ++makeExcerpt(declFile, 'search') :marked Run the app again, go to the *Dashboard*, and enter some text in the search box. @@ -554,7 +543,8 @@ block filetree .children .file app.component.ts .file app.component.css - .file app.routes.ts + .file app.module.ts + .file app.routing.ts .file dashboard.component.css .file dashboard.component.html .file dashboard.component.ts @@ -566,7 +556,7 @@ block filetree .file hero-search.component.css (new) .file hero-search.component.ts (new) .file hero-search.service.ts (new) - .file rxjs-operators.ts + .file rxjs-extensions.ts .file hero.service.ts .file heroes.component.css .file heroes.component.html @@ -593,12 +583,13 @@ block filetree - We updated our components to allow adding, editing and deleting of heroes. - We configured an in-memory web API. - We learned how to use !{_Observable}s. - + Here are the files we added or changed in this chapter. block file-summary +makeTabs( `toh-6/ts/app/app.component.ts, + toh-6/ts/app/app.module.ts, toh-6/ts/app/heroes.component.ts, toh-6/ts/app/heroes.component.html, toh-6/ts/app/heroes.component.css, @@ -606,8 +597,9 @@ block file-summary toh-6/ts/app/hero-detail.component.html, toh-6/ts/app/hero.service.ts, toh-6/ts/app/in-memory-data.service.ts`, - null, + ',,,,,,,,', `app.comp...ts, + app.mod...ts, heroes.comp...ts, heroes.comp...html, heroes.comp...css, @@ -622,11 +614,11 @@ block file-summary toh-6/ts/app/hero-search.component.ts, toh-6/ts/app/hero-search.component.html, toh-6/ts/app/hero-search.component.css, - toh-6/ts/app/rxjs-operators.ts`, + toh-6/ts/app/rxjs-extensions.ts`, null, `hero-search.service.ts, hero-search.component.ts, - hero-search.service.html, + hero-search.component.html, hero-search.component.css, - rxjs-operators.ts` + rxjs-extensions.ts` ) diff --git a/public/docs/ts/latest/tutorial/toh-pt6.jade b/public/docs/ts/latest/tutorial/toh-pt6.jade index 738302111b..1843772aab 100644 --- a/public/docs/ts/latest/tutorial/toh-pt6.jade +++ b/public/docs/ts/latest/tutorial/toh-pt6.jade @@ -5,7 +5,6 @@ block includes - var _Http = 'Http'; // Angular `Http` library name. - var _Angular_Http = 'Angular Http' - var _Angular_http_library = 'Angular HTTP library' - - var _HTTP_PROVIDERS = 'HTTP_PROVIDERS' - var _HttpModule = 'HttpModule' - var _JSON_stringify = 'JSON.stringify' @@ -54,23 +53,24 @@ block http-library block http-providers :marked Our app will depend upon the Angular `http` service which itself depends upon other supporting services. - The `HttpModule` from `@angular/http` library holds providers for the complete set of http services. + The `HttpModule` from `@angular/http` library holds providers for the complete set of `http` services. -:marked - We should be able to access `!{_Http}` services from anywhere in the application. - So we register them in the `imports` array of app.module.ts where we - bootstrap the application and its root `AppComponent`. + We should be able to access `http` services from anywhere in the application. + So we register them in the `imports` array of `app.module.ts` where we + bootstrap the application and its root `AppComponent`. -+makeExample('app/app.module.2.ts','', 'app.module.ts (v.1)') + +makeExcerpt('app/app.module.ts (v1)') -:marked - Notice that we supply `!{_HttpModule}` as part of the *imports* !{_array} in root NgModule `AppModule`. + :marked + Notice that we supply `!{_HttpModule}` as part of the *imports* !{_array} in root NgModule `AppModule`. .l-main-section :marked ## Simulating the web API - We recommend registering application-wide services in the root `NgModule` *providers*. + We recommend registering application-wide services in the root + `!{_AppModuleVsAppComp}` *providers*. Here we're + registering in `main` for a special reason. Our application is in the early stages of development and far from ready for production. We don't even have a web server that can handle requests for heroes. @@ -78,9 +78,13 @@ block http-providers We're going to *trick* the HTTP client into fetching and saving data from a mock service, the *in-memory web API*. + The application itself doesn't need to know and + shouldn't know about this. So we'll slip the in-memory web API into the + configuration *above* the `AppComponent`. - Here is a version of `app.module.ts` that performs this trick -+makeExample('app/app.module.1.ts', '', 'app.module.ts (final)') + Here is a version of !{_appModuleTsVsMainTs} that performs this trick: + ++makeExcerpt(_appModuleTsVsMainTs, 'v2') block backend :marked @@ -510,11 +514,12 @@ block observable-transformers +makeExample('app/dashboard.component.html') +- var _declarations = _docsFor == 'dart' ? 'directives' : 'declarations' +- var declFile = _docsFor == 'dart' ? 'app/dashboard.component.ts' : 'app/app.module.ts' :marked - And finally, we import the `HeroSearchComponent` and add it to the `declarations` !{_array} in - `app.module.ts`. + And finally, we import the `HeroSearchComponent` and add it to the `!{_declarations}` !{_array}: -+makeExcerpt('app/app.module.2.ts', 'hero-search-declaration') ++makeExcerpt(declFile, 'search') :marked Run the app again, go to the *Dashboard*, and enter some text in the search box. @@ -551,7 +556,7 @@ block filetree .file hero-search.component.css (new) .file hero-search.component.ts (new) .file hero-search.service.ts (new) - .file rxjs-operators.ts + .file rxjs-extensions.ts .file hero.service.ts .file heroes.component.css .file heroes.component.html @@ -609,12 +614,11 @@ block file-summary toh-6/ts/app/hero-search.component.ts, toh-6/ts/app/hero-search.component.html, toh-6/ts/app/hero-search.component.css, - toh-6/ts/app/rxjs-operators.ts`, + toh-6/ts/app/rxjs-extensions.ts`, null, `hero-search.service.ts, hero-search.component.ts, - hero-search.service.html, + hero-search.component.html, hero-search.component.css, - hero-search.component.css, - rxjs-operators.ts` + rxjs-extensions.ts` ) From 35b54383c227781640e151c13f21a5ee68ff462e Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Fri, 12 Aug 2016 13:39:17 -0700 Subject: [PATCH 012/247] docs(toh-5): add file to cache (#2102) * toh-pt5: cached version before new router was introduced * toh-pt5: refreshed cached copy from latest (post-RC5) --- public/docs/ts/_cache/tutorial/toh-pt5.jade | 740 ++++++++++++++++++++ scripts/cache.sh | 1 + 2 files changed, 741 insertions(+) create mode 100644 public/docs/ts/_cache/tutorial/toh-pt5.jade diff --git a/public/docs/ts/_cache/tutorial/toh-pt5.jade b/public/docs/ts/_cache/tutorial/toh-pt5.jade new file mode 100644 index 0000000000..60954ae6e1 --- /dev/null +++ b/public/docs/ts/_cache/tutorial/toh-pt5.jade @@ -0,0 +1,740 @@ +include ../_util-fns + +:marked + # Routing Around the App + We received new requirements for our Tour of Heroes application: + * Add a *Dashboard* view. + * Navigate between the *Heroes* and *Dashboard* views. + * Clicking on a hero in either view navigates to a detail view of the selected hero. + * Clicking a *deep link* in an email opens the detail view for a particular hero; + + When we’re done, users will be able to navigate the app like this: +figure.image-display + img(src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations") +:marked + We'll add Angular’s *Component Router* to our app to satisfy these requirements. +.l-sub-section + :marked + The [Routing and Navigation](../guide/router.html) chapter covers the router in more detail + than we will in this tutorial. + +:marked + Run the for this part. + +.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 + To see the URL changes in the browser address bar, + pop out the preview window by clicking the blue 'X' button in the upper right corner: + +.l-main-section +:marked + ## Where We Left Off + Before we continue with our Tour of Heroes, let’s verify that we have the following structure after adding our hero service + and hero detail component. If not, we’ll need to go back and follow the previous chapters. + +.filetree + .file angular2-tour-of-heroes + .children + .file app + .children + .file app.component.ts + .file app.module.ts + .file hero.ts + .file hero-detail.component.ts + .file hero.service.ts + .file main.ts + .file mock-heroes.ts + .file node_modules ... + .file typings ... + .file index.html + .file package.json + .file styles.css + .file systemjs.config.js + .file tsconfig.json + .file typings.json +:marked + ### Keep the app transpiling and running + Open a terminal/console window and enter the following command to + start the TypeScript compiler, start the server, and watch for changes: + +code-example(language="bash"). + npm start + +:marked + The application runs and updates automatically as we continue to build the Tour of Heroes. + + ## Action plan + Here's our plan: + + * Turn `AppComponent` into an application shell that only handles navigation + * Relocate the *Heroes* concerns within the current `AppComponent` to a separate `HeroesComponent` + * Add routing + * Create a new `DashboardComponent` + * Tie the *Dashboard* into the navigation structure + +.l-sub-section + :marked + *Routing* is another name for *navigation*. The *router* is the mechanism for navigating from view to view. + +.l-main-section +:marked + ## Splitting the *AppComponent* + + Our current app loads `AppComponent` and immediately displays the list of heroes. + + Our revised app should present a shell with a choice of views (*Dashboard* and *Heroes*) and then default to one of them. + + The `AppComponent` should only handle navigation. + Let's move the display of *Heroes* out of `AppComponent` and into its own `HeroesComponent`. + + ### *HeroesComponent* + `AppComponent` is already dedicated to *Heroes*. + Instead of moving anything out of `AppComponent`, we'll just rename it `HeroesComponent` + and create a new `AppComponent` shell separately. + + The steps are to rename: + * `app.component.ts` file to `heroes.component.ts` + * `AppComponent` class to `HeroesComponent` + * Selector `my-app` to `my-heroes` + +:marked ++makeExample('toh-5/ts/app/heroes.component.ts', 'heroes-component-renaming', 'app/heroes.component.ts (showing renamings only)')(format=".") + +:marked + ## Create *AppComponent* + The new `AppComponent` will be the application shell. + It will have some navigation links at the top and a display area below for the pages we navigate to. + + The initial steps are: + + * create a new file named `app.component.ts`. + * define an `AppComponent` class. + * `export` it so we can reference it during bootstrapping in `app.module.ts`. + * expose an application `title` property. + * add the `@Component` metadata decorator above the class with a `my-app` selector. + * add a template with `

    ` tags surrounding a binding to the `title` property. + * add the `` tags to the template so we still see the heroes. + * add the `HeroesComponent` to the root NgModule's `declarations` array so Angular recognizes the `` tags. + * add the `HeroService` to the root NgModule's `providers` array because we'll need it in every other view. + * add the supporting `import` statements. + + Our first draft looks like this: ++makeTabs( + `toh-5/ts/app/app.component.1.ts, + toh-5/ts/app/app.module.1.ts`, + ',', + `app/app.component.ts (v1), + app/app.module.ts (v1)`) + +:marked +.callout.is-critical + header Remove HeroService from the HeroesComponent providers + :marked + Go back to the `HeroesComponent` and **remove the `HeroService`** from its `providers` array. + We are *promoting* this service from the `HeroesComponent` to the root `NgModule`. + We ***do not want two copies*** of this service at two different levels of our app. +:marked + The app still runs and still displays heroes. + Our refactoring of `AppComponent` into a new `AppComponent` and a `HeroesComponent` worked! + We have done no harm. + +:marked + ## Add Routing + + We're ready to take the next step. + Instead of displaying heroes automatically, we'd like to show them *after* the user clicks a button. + In other words, we'd like to navigate to the list of heroes. + + We'll need the Angular *Component Router*. + + ### Set the base tag + Open the `index.html` and add `` at the top of the `` section. ++makeExample('toh-5/ts/index.html', 'base-href', 'index.html (base href)')(format=".") +.callout.is-important + header base href is essential + :marked + See the *base href* section of the [Router](../guide/router.html#!#base-href) chapter to learn why this matters. +:marked + The Angular router is a combination of multiple provided services (`RouterModule`), multiple directives (`RouterOutlet, + RouterLink, RouterLinkActive`), and a configuration (`Routes`). We'll configure our routes first: + + ### Configure the routes + + The *Component Router* is an external, optional Angular NgModule called `RouterModule`. + + Our application doesn't have any routes yet. + Start by creating a configuration file for the application routes. + *Routes* tell the router which views to display when a user clicks a link or + pastes a URL into the browser address bar. + + Our first route goes to the `HeroesComponent`. ++makeExample('toh-5/ts/app/app.routing.1.ts', 'routing-config', 'app/app.routing.ts (heroes route)')(format=".") +:marked + The `Routes` are an array of *route definitions*. + We have only one route definition at the moment but rest assured, we'll add more. + + This *route definition* has two parts: + * **path**: the router matches this route's path to the URL in the browser address bar (`/heroes`). + + * **component**: the component that the router should create when navigating to this route (`HeroesComponent`). + +.l-sub-section + :marked + Learn more about defining routes with Routes in the [Routing](../guide/router.html) chapter. + +:marked + We'll export the `routing` constant using the **RouterModule.forRoot** method with our array of routes. + This returns a configured router module we'll add to our root NgModule, `AppModule`. + ++makeExample('toh-5/ts/app/app.routing.1.ts', 'routing-export', 'app/app.routing.ts (routing export)')(format=".") +.l-sub-section + :marked + We call the `forRoot` method because we're providing a configured router at the _root_ of the application. + The `forRoot` method gives us the Router service providers and directives needed for routing. + +:marked + ### Make the router available. + We've setup our initial routes in our `app.routing.ts` file. Now we'll add it to our root NgModule. + + We'll import our `routing` constant from our `app.routing.ts` file and add it root NgModule's `imports` array. + + We'll also import our `HeroesComponent` and add it to our `declarations` array. + ++makeExample('toh-5/ts/app/app.module.2.ts', '', 'app/app.module.ts')(format=".") + +:marked + ### Router Outlet + + If we paste the path, `/heroes`, into the browser address bar, + the router should match it to the `heroes` route and display the `HeroesComponent`. + But where? + + We have to ***tell it where*** by adding `` marker tags to the bottom of the template. + `RouterOutlet` is one of the directives provided by the `RouterModule`. + The router displays each component immediately below the `` as we navigate through the application. + + ### Router Links + We don't really expect users to paste a route URL into the address bar. + We add an anchor tag to the template which, when clicked, triggers navigation to the `HeroesComponent`. + + The revised template looks like this: ++makeExample('toh-5/ts/app/app.component.2.ts', 'template', 'app/app.component.ts (template v1)')(format=".") +:marked + Notice the `routerLink` binding in the anchor tag. + We bind the `RouterLink` directive (another of the `RouterModule` directives) to a string + that tells the router where to navigate when the user clicks the link. + + Since our link is not dynamic, we define a *routing instruction* with a **one-time binding** to our route **path**. + Looking back at the route configuration, we confirm that `'/heroes'` is the path of the route to the `HeroesComponent`. +.l-sub-section + :marked + For more dynamic router links, learn about the *link parameters array* in the [Routing](../guide/router.html#link-parameters-array) chapter. +:marked + Refresh the browser. We see only the app title. We don't see the heroes list. +.l-sub-section + :marked + The browser's address bar shows `/`. + The route path to `HeroesComponent` is `/heroes`, not `/`. + We don't have a route that matches the path `/`, so there is nothing to show. + That's something we'll want to fix. +:marked + We click the "Heroes" navigation link, the browser bar updates to `/heroes`, + and now we see the list of heroes. We are navigating at last! + + At this stage, our `AppComponent` looks like this. ++makeExample('toh-5/ts/app/app.component.2.ts',null, 'app/app.component.ts (v2)') +:marked + The *AppComponent* is now attached to a router and displaying routed views. + For this reason and to distinguish it from other kinds of components, + we call this type of component a *Router Component*. + + +:marked + ## Add a *Dashboard* + Routing only makes sense when we have multiple views. We need another view. + + Create a placeholder `DashboardComponent` that gives us something to navigate to and from. ++makeExample('toh-5/ts/app/dashboard.component.1.ts',null, 'app/dashboard.component.ts (v1)')(format=".") +:marked + We’ll come back and make it more useful later. + + ### Configure the dashboard route + Go back to `app.routing.ts` and teach it to navigate to the dashboard. + + Import the `DashboardComponent` so we can reference it in the dashboard route definition. + + Add the following `'Dashboard'` route definition to the `Routes` array of definitions. ++makeExample('toh-5/ts/app/app.routing.2.ts','dashboard-route', 'app/app.routing.ts (Dashboard route)')(format=".") + +:marked + We also need to add the `DashboardComponent` to our root NgModule's `declarations`. + ++makeExample('toh-5/ts/app/app.module.3.ts','dashboard-declaration', 'app/app.module.ts (Dashboard declaration)')(format=".") + +.l-sub-section + :marked + **Redirect** + + We want the app to show the dashboard when it starts and + we want to see a nice URL in the browser address bar that says `/dashboard`. + Remember that the browser launches with `/` in the address bar. + We can use a redirect route to make this happen. + ++makeExample('toh-5/ts/app/app.routing.2.ts','redirect-route', 'app/app.routing.ts (Redirect route)')(format=".") + +.l-sub-section + :marked + Learn about the *redirects* in the [Routing](../guide/router.html#!#redirect) chapter. + +:marked + Finally, add a dashboard navigation link to the template, just above the *Heroes* link. + ++makeExample('toh-5/ts/app/app.component.3.ts','template', 'app/app.component.ts (template)')(format=".") +.l-sub-section + :marked + We nestled the two links within `