From 502767fb2b7aa6ce15ffe8c94b45af67c3b4e3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Rodr=C3=ADguez?= Date: Sun, 5 Feb 2017 03:12:47 +0100 Subject: [PATCH 001/216] chore: lock to Angular 2.4.5 (#3188) --- public/docs/_examples/package.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index a1e0904223..efaf9281be 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -12,18 +12,18 @@ "author": "", "license": "MIT", "dependencies": { - "@angular/common": "~2.4.0", - "@angular/compiler": "~2.4.0", - "@angular/compiler-cli": "~2.4.0", - "@angular/core": "~2.4.0", - "@angular/forms": "~2.4.0", - "@angular/http": "~2.4.0", - "@angular/platform-browser": "~2.4.0", - "@angular/platform-browser-dynamic": "~2.4.0", - "@angular/platform-server": "~2.4.0", - "@angular/router": "~3.4.0", + "@angular/common": "2.4.5", + "@angular/compiler": "2.4.5", + "@angular/compiler-cli": "2.4.5", + "@angular/core": "2.4.5", + "@angular/forms": "2.4.5", + "@angular/http": "2.4.5", + "@angular/platform-browser": "2.4.5", + "@angular/platform-browser-dynamic": "2.4.5", + "@angular/platform-server": "2.4.5", + "@angular/router": "3.4.5", "@angular/tsc-wrapped": "^0.5.0", - "@angular/upgrade": "~2.4.0", + "@angular/upgrade": "2.4.5", "angular-in-memory-web-api": "~0.2.4", "core-js": "^2.4.1", "rxjs": "5.0.1", From 6732babf23489f4fc6b1cb255edd1e892d1fa973 Mon Sep 17 00:00:00 2001 From: Indri Muska Date: Sun, 5 Feb 2017 16:43:11 +0100 Subject: [PATCH 002/216] docs(webpack): missing commas in snippet code (#3196) --- .../_examples/webpack/ts-snippets/webpack.config.snippets.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/docs/_examples/webpack/ts-snippets/webpack.config.snippets.ts b/public/docs/_examples/webpack/ts-snippets/webpack.config.snippets.ts index a15d4ee215..251e1b8ed8 100644 --- a/public/docs/_examples/webpack/ts-snippets/webpack.config.snippets.ts +++ b/public/docs/_examples/webpack/ts-snippets/webpack.config.snippets.ts @@ -34,11 +34,11 @@ output: { // #docregion loaders rules: [ { - test: /\.ts$/ + test: /\.ts$/, loader: 'awesome-typescript-loader' }, { - test: /\.css$/ + test: /\.css$/, loaders: 'style-loader!css-loader' } ] From eb372a9b392c2ecf116b3be54fb31b5d429da020 Mon Sep 17 00:00:00 2001 From: Kanstantsin Klimashevich Date: Mon, 6 Feb 2017 01:25:05 +0300 Subject: [PATCH 003/216] docs(router): fix Router.forRoot -> RouterModule.forRoot (#3172) --- public/docs/ts/latest/guide/router.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/docs/ts/latest/guide/router.jade b/public/docs/ts/latest/guide/router.jade index 4186c55ad0..462b5ad421 100644 --- a/public/docs/ts/latest/guide/router.jade +++ b/public/docs/ts/latest/guide/router.jade @@ -113,7 +113,7 @@ include ../../../_includes/_see-addr-bar a#example-config :marked The `appRoutes` array of *routes* describes how to navigate. - Pass it to the `Router.forRoot` method in the module `imports` to configure the router. + Pass it to the `RouterModule.forRoot` method in the module `imports` to configure the router. Each `Route` maps a URL `path` to a component. There are _no leading slashes_ in the _path_. From 67a389f6810070d93466cdddf8b0e39297699fc1 Mon Sep 17 00:00:00 2001 From: Wassim Chegham Date: Mon, 6 Feb 2017 00:06:58 +0100 Subject: [PATCH 004/216] doc(angular.io): update twitter account (#3197) --- public/news.jade | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/news.jade b/public/news.jade index 1fb53906cd..b63962ae61 100644 --- a/public/news.jade +++ b/public/news.jade @@ -102,11 +102,11 @@ .article-card .title a( - href="http://twitter.com/angularjs" + href="http://twitter.com/angular" class="twitter-follow-button" data-show-count="false" - ) Follow @angularjs + ) Follow @angular p. + href="http://twitter.com/angular" data-widget-id="700150278465523713"> From 56c030cb5d39436dbb8ba3c94b60c782077935f1 Mon Sep 17 00:00:00 2001 From: robshep Date: Mon, 6 Feb 2017 18:27:52 +0000 Subject: [PATCH 005/216] chore(toh-5): Fix broken link to master style in TOH pt5 (#3201) --- public/docs/ts/latest/tutorial/toh-pt5.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/docs/ts/latest/tutorial/toh-pt5.jade b/public/docs/ts/latest/tutorial/toh-pt5.jade index baca471527..aef0351f85 100644 --- a/public/docs/ts/latest/tutorial/toh-pt5.jade +++ b/public/docs/ts/latest/tutorial/toh-pt5.jade @@ -881,7 +881,7 @@ block style-urls +makeExcerpt('src/styles.css (excerpt)', 'toh') -- var styles_css = 'https://raw.githubusercontent.com/angular/angular.io/master/public/docs/_examples/_boilerplate/styles.css' +- var styles_css = 'https://raw.githubusercontent.com/angular/angular.io/master/public/docs/_examples/_boilerplate/src/styles.css' :marked Create the file styles.css, if it doesn't exist already. From dc4da634c40560e4eda55814676bc96a230428dc Mon Sep 17 00:00:00 2001 From: David Rabkin Date: Mon, 6 Feb 2017 10:46:48 -0800 Subject: [PATCH 006/216] Update 2 Twitter Handels in harp.json (#2360) Currently, the links to Twitter on Kapunahele Wong's and Ward Bell's bios both point to https://twitter.com/undefined. These links are accessible when their bios are opened. This PR adds their proper Twitter handle, so their respective links point to the right place. --- harp.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/harp.json b/harp.json index 2a001701e6..9455f2c880 100644 --- a/harp.json +++ b/harp.json @@ -361,6 +361,7 @@ "name": "Ward Bell", "picture": "/resources/images/bios/wardbell.jpg", "website": "https://github.com/wardbell", + "twitter": "wardbell", "bio": "Ward is an all-around developer with JavaScript, node, and .net chops. He's a frequent conference speaker and podcaster, trainer, Google Developer Expert for Angular, Microsoft MVP, and PluralSight author. He is also president of IdeaBlade, an enterprise software consulting firm and the makers of breeze.js. He would like to get more sleep and spend more time in the mountains.", "type": "Community" }, @@ -509,6 +510,7 @@ "name": "Kapunahele Wong", "picture": "/resources/images/bios/kapunahelewong.jpg", "website": " https://github.com/kapunahelewong", + "twitter": "kapunahele", "bio": "Kapunahele is a front-end developer at Capital One. She loves just about anything to do with JavaScript, Angular and electronics. She enjoys mapping Hawaiian star names and constellations to Western ones and loves dancing native Hawaiian hula.", "type": "Community" }, From b2f41484721265026c87fb5c8780a8a4a57d5b61 Mon Sep 17 00:00:00 2001 From: Ward Bell Date: Mon, 6 Feb 2017 18:35:49 -0800 Subject: [PATCH 007/216] chore(quickstart): restore app.module and main (#3166) We seemed to create more confusion by omitting app.module (and main) in QS than we gained in simplicity of QS Every other example requires these files. This PR restores them to QS _but doesn't talk about them_ in QS, leaving _that_ to the Setup guide. --- .../src/systemjs.config.web.build.js | 52 ------------------- .../_boilerplate/src/systemjs.config.web.js | 52 ------------------- .../docs/_examples/quickstart/ts/plnkr.json | 2 + .../_examples/quickstart/ts/src/index.html | 5 -- public/docs/ts/latest/cli-quickstart.jade | 32 ++++++------ public/docs/ts/latest/guide/_data.json | 1 - public/docs/ts/latest/guide/appmodule.jade | 37 +++++++------ public/docs/ts/latest/guide/architecture.jade | 2 +- .../ts/latest/guide/learning-angular.jade | 5 +- public/docs/ts/latest/guide/ngmodule.jade | 4 +- public/docs/ts/latest/guide/setup.jade | 24 ++++----- 11 files changed, 50 insertions(+), 166 deletions(-) diff --git a/public/docs/_examples/_boilerplate/src/systemjs.config.web.build.js b/public/docs/_examples/_boilerplate/src/systemjs.config.web.build.js index bfb9dbcd99..c27642ce02 100644 --- a/public/docs/_examples/_boilerplate/src/systemjs.config.web.build.js +++ b/public/docs/_examples/_boilerplate/src/systemjs.config.web.build.js @@ -79,58 +79,6 @@ } }); - if (global.autoBootstrap) { bootstrap(); } - - // Bootstrap with a default `AppModule` - // ignore an `app/app.module.ts` and `app/main.ts`, even if present - // This function exists primarily (exclusively?) for the QuickStart - function bootstrap() { - console.log('Auto-bootstrapping'); - - // Stub out `app/main.ts` so System.import('app') doesn't fail if called in the index.html - System.set(System.normalizeSync('app/main.ts'), System.newModule({ })); - - // bootstrap and launch the app (equivalent to standard main.ts) - Promise.all([ - System.import('@angular/platform-browser-dynamic'), - getAppModule() - ]) - .then(function (imports) { - var platform = imports[0]; - var app = imports[1]; - platform.platformBrowserDynamic().bootstrapModule(app.AppModule); - }) - .catch(function(err){ console.error(err); }); - } - - // Make the default AppModule - // returns a promise for the AppModule - function getAppModule() { - console.log('Making a bare-bones, default AppModule'); - - return Promise.all([ - System.import('@angular/core'), - System.import('@angular/platform-browser'), - System.import('app/app.component') - ]) - .then(function (imports) { - - var core = imports[0]; - var browser = imports[1]; - var appComp = imports[2].AppComponent; - - var AppModule = function() {} - - AppModule.annotations = [ - new core.NgModule({ - imports: [ browser.BrowserModule ], - declarations: [ appComp ], - bootstrap: [ appComp ] - }) - ] - return {AppModule: AppModule}; - }) - } })(this); /* diff --git a/public/docs/_examples/_boilerplate/src/systemjs.config.web.js b/public/docs/_examples/_boilerplate/src/systemjs.config.web.js index 576bded343..dc0234a172 100644 --- a/public/docs/_examples/_boilerplate/src/systemjs.config.web.js +++ b/public/docs/_examples/_boilerplate/src/systemjs.config.web.js @@ -66,58 +66,6 @@ } }); - if (global.autoBootstrap) { bootstrap(); } - - // Bootstrap with a default `AppModule` - // ignore an `app/app.module.ts` and `app/main.ts`, even if present - // This function exists primarily (exclusively?) for the QuickStart - function bootstrap() { - console.log('Auto-bootstrapping'); - - // Stub out `app/main.ts` so System.import('app') doesn't fail if called in the index.html - System.set(System.normalizeSync('app/main.ts'), System.newModule({ })); - - // bootstrap and launch the app (equivalent to standard main.ts) - Promise.all([ - System.import('@angular/platform-browser-dynamic'), - getAppModule() - ]) - .then(function (imports) { - var platform = imports[0]; - var app = imports[1]; - platform.platformBrowserDynamic().bootstrapModule(app.AppModule); - }) - .catch(function(err){ console.error(err); }); - } - - // Make the default AppModule - // returns a promise for the AppModule - function getAppModule() { - console.log('Making a bare-bones, default AppModule'); - - return Promise.all([ - System.import('@angular/core'), - System.import('@angular/platform-browser'), - System.import('app/app.component') - ]) - .then(function (imports) { - - var core = imports[0]; - var browser = imports[1]; - var appComp = imports[2].AppComponent; - - var AppModule = function() {} - - AppModule.annotations = [ - new core.NgModule({ - imports: [ browser.BrowserModule ], - declarations: [ appComp ], - bootstrap: [ appComp ] - }) - ] - return {AppModule: AppModule}; - }) - } })(this); /* diff --git a/public/docs/_examples/quickstart/ts/plnkr.json b/public/docs/_examples/quickstart/ts/plnkr.json index 5fb55b50ad..8edf7c25ea 100644 --- a/public/docs/_examples/quickstart/ts/plnkr.json +++ b/public/docs/_examples/quickstart/ts/plnkr.json @@ -3,6 +3,8 @@ "basePath": "src/", "files": [ "app/app.component.ts", + "app/app.module.ts", + "main.ts", "index.html" ], "open": "app/app.component.ts", diff --git a/public/docs/_examples/quickstart/ts/src/index.html b/public/docs/_examples/quickstart/ts/src/index.html index a6d62dae0a..21fb56edb9 100644 --- a/public/docs/_examples/quickstart/ts/src/index.html +++ b/public/docs/_examples/quickstart/ts/src/index.html @@ -16,11 +16,6 @@ - - - - - diff --git a/public/docs/_examples/reactive-forms/ts/src/app/main-final.ts b/public/docs/_examples/reactive-forms/ts/src/main-final.ts similarity index 78% rename from public/docs/_examples/reactive-forms/ts/src/app/main-final.ts rename to public/docs/_examples/reactive-forms/ts/src/main-final.ts index 1a5e243fa0..7572d1f1d3 100644 --- a/public/docs/_examples/reactive-forms/ts/src/app/main-final.ts +++ b/public/docs/_examples/reactive-forms/ts/src/main-final.ts @@ -1,5 +1,5 @@ // tslint:disable:no-unused-variable import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; -import { AppModule } from './app.module'; +import { AppModule } from './app/app.module'; platformBrowserDynamic().bootstrapModule(AppModule); From 905733593ba10a2a18572bec21ee175fbb5ab1f8 Mon Sep 17 00:00:00 2001 From: Josh Schneider Date: Mon, 6 Feb 2017 18:59:21 -0800 Subject: [PATCH 010/216] docs (router): fix type in router.jade (#3205) Fix "Since the admin dashboard RouterLink is an empty path route in the AdminModule," ... "AdminModule" s/b "AdminComponent," AFICT. --- public/docs/ts/latest/guide/router.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/docs/ts/latest/guide/router.jade b/public/docs/ts/latest/guide/router.jade index 462b5ad421..bc13670d48 100644 --- a/public/docs/ts/latest/guide/router.jade +++ b/public/docs/ts/latest/guide/router.jade @@ -1941,7 +1941,7 @@ a#can-activate-guard .l-sub-section :marked - Since the admin dashboard `RouterLink` is an empty path route in the `AdminModule`, it + Since the admin dashboard `RouterLink` is an empty path route in the `AdminComponent`, it is considered a match to any route within the admin feature area. You only want the `Dashboard` link to be active when the user visits that route. Add an additional binding to the `Dashboard` routerLink, From 390e28080cb5ea78d31e2a26260f16781ce137ad Mon Sep 17 00:00:00 2001 From: Josh Schneider Date: Mon, 6 Feb 2017 19:03:30 -0800 Subject: [PATCH 011/216] docs(di): fix AppModule providers in dependency-injection.jade (#3206) "Here's our AppModule where we register a `Logger`, a `UserService`, and an `APP_CONFIG` provider." No Logger appears to be registered in the source code. --- public/docs/ts/latest/guide/dependency-injection.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/docs/ts/latest/guide/dependency-injection.jade b/public/docs/ts/latest/guide/dependency-injection.jade index 4c4d95b174..559656cbf8 100644 --- a/public/docs/ts/latest/guide/dependency-injection.jade +++ b/public/docs/ts/latest/guide/dependency-injection.jade @@ -259,7 +259,7 @@ block register-provider-ngmodule We can either register a provider within an [NgModule](ngmodule.html) or in application components ### Registering providers in an NgModule - Here's our AppModule where we register a `Logger`, a `UserService`, and an `APP_CONFIG` provider. + Here's our AppModule where we register a `UserService` and an `APP_CONFIG` provider. - var app_module_ts = 'src/app/app.module.ts'; +makeExcerpt(app_module_ts + ' (excerpt)', 'ngmodule', app_module_ts, { otl: /(providers:)/ }) From f24b830c8a69eb109e7bfec6508208006ef7ac5c Mon Sep 17 00:00:00 2001 From: Ward Bell Date: Mon, 6 Feb 2017 19:06:13 -0800 Subject: [PATCH 012/216] docs(template-syntax/structural-directives): refresh both guides for style, accuracy, understanding (#3110) Move details of structural directives from template-syntax to structural-directives guide Add to structural-directives Fix samples in both guides Touch up glossary Better conformance to google doc guidelines: we->you closes #2303, #2885 --- .../ngcontainer/ts/example-config.json | 0 .../docs/_examples/ngcontainer/ts/plnkr.json | 11 + .../ngcontainer/ts/src/app/app.component.css | 34 + .../ngcontainer/ts/src/app/app.component.html | 279 ++++ .../ngcontainer/ts/src/app/app.component.ts | 25 + .../ngcontainer/ts/src/app/app.module.ts | 19 + .../ts/src/app/content.component.ts | 16 + .../ngcontainer/ts/src/app/hero.components.ts | 43 + .../_examples/ngcontainer/ts/src/app/hero.ts | 13 + .../_examples/ngcontainer/ts/src/index.html | 26 + .../docs/_examples/ngcontainer/ts/src/main.ts | 6 + .../structural-directives/e2e-spec.ts | 90 +- .../structural-directives/ts/plnkr.json | 6 +- .../ts/src/app/app.component.css | 70 + .../ts/src/app/app.component.html | 252 ++++ .../ts/src/app/app.component.ts | 24 + .../ts/src/app/app.module.ts | 19 +- .../ts/src/app/heavy-loader.component.ts | 35 - .../ts/src/app/hero-switch.components.ts | 43 + .../structural-directives/ts/src/app/hero.ts | 13 + .../ts/src/app/scrap.txt | 21 + .../app/structural-directives.component.html | 109 -- .../app/structural-directives.component.ts | 19 - .../ts/src/app/unless.directive.ts | 58 +- .../structural-directives/ts/src/index.html | 2 +- .../ts/src/app/app.component.css | 17 + .../ts/src/app/app.component.html | 355 +++-- .../ts/src/app/app.component.ts | 143 +- .../ts/src/app/app.module.1.ts | 11 +- .../template-syntax/ts/src/app/app.module.ts | 10 +- .../ts/src/app/hero-detail.component.ts | 20 +- .../ts/src/app/hero-form.component.html | 16 + .../ts/src/app/hero-form.component.ts | 31 + .../ts/src/app/hero-switch.components.ts | 42 + .../template-syntax/ts/src/app/hero.ts | 37 +- .../template-syntax/ts/src/index.html | 1 - .../app/hero/hero-detail.component.spec.ts | 4 +- public/docs/ts/latest/glossary.jade | 44 +- .../ts/latest/guide/attribute-directives.jade | 15 +- public/docs/ts/latest/guide/change-log.jade | 8 +- public/docs/ts/latest/guide/ngcontainer.jade | 218 +++ .../latest/guide/structural-directives.jade | 738 ++++++---- .../docs/ts/latest/guide/template-syntax.jade | 1255 +++++++++-------- .../devguide/ngcontainer/hero-traits-bad.png | Bin 0 -> 2417 bytes .../devguide/ngcontainer/hero-traits-good.png | Bin 0 -> 3216 bytes .../structural-directives/bad-paragraph.png | Bin 0 -> 2699 bytes .../structural-directives/bad-select.png | Bin 0 -> 2356 bytes .../element-display-in-dom.png | Bin 0 -> 6858 bytes .../element-not-in-dom.png | Bin 6084 -> 4639 bytes .../structural-directives/good-paragraph.png | Bin 0 -> 2822 bytes .../heavy-loader-toggle.gif | Bin 157202 -> 0 bytes .../structural-directives/hero-div-in-dom.png | Bin 0 -> 3525 bytes .../ngSwitch-rendering.png | Bin 0 -> 18177 bytes .../select-ngcontainer-anim.gif | Bin 0 -> 34430 bytes .../template-in-out-of-a2.png | Bin 35047 -> 0 bytes .../template-rendering.png | Bin 0 -> 7069 bytes .../structural-directives/unless-anim.gif | Bin 0 -> 17872 bytes .../template-syntax/ng-for-track-by-anim.gif | Bin 200223 -> 89008 bytes .../template-syntax/ng-switch-anim.gif | Bin 33806 -> 0 bytes .../devguide/template-syntax/switch-anim.gif | Bin 0 -> 76823 bytes 60 files changed, 2820 insertions(+), 1378 deletions(-) create mode 100644 public/docs/_examples/ngcontainer/ts/example-config.json create mode 100644 public/docs/_examples/ngcontainer/ts/plnkr.json create mode 100644 public/docs/_examples/ngcontainer/ts/src/app/app.component.css create mode 100644 public/docs/_examples/ngcontainer/ts/src/app/app.component.html create mode 100644 public/docs/_examples/ngcontainer/ts/src/app/app.component.ts create mode 100644 public/docs/_examples/ngcontainer/ts/src/app/app.module.ts create mode 100644 public/docs/_examples/ngcontainer/ts/src/app/content.component.ts create mode 100644 public/docs/_examples/ngcontainer/ts/src/app/hero.components.ts create mode 100644 public/docs/_examples/ngcontainer/ts/src/app/hero.ts create mode 100644 public/docs/_examples/ngcontainer/ts/src/index.html create mode 100644 public/docs/_examples/ngcontainer/ts/src/main.ts create mode 100644 public/docs/_examples/structural-directives/ts/src/app/app.component.css create mode 100644 public/docs/_examples/structural-directives/ts/src/app/app.component.html create mode 100644 public/docs/_examples/structural-directives/ts/src/app/app.component.ts delete mode 100644 public/docs/_examples/structural-directives/ts/src/app/heavy-loader.component.ts create mode 100644 public/docs/_examples/structural-directives/ts/src/app/hero-switch.components.ts create mode 100644 public/docs/_examples/structural-directives/ts/src/app/hero.ts create mode 100644 public/docs/_examples/structural-directives/ts/src/app/scrap.txt delete mode 100644 public/docs/_examples/structural-directives/ts/src/app/structural-directives.component.html delete mode 100644 public/docs/_examples/structural-directives/ts/src/app/structural-directives.component.ts create mode 100644 public/docs/_examples/template-syntax/ts/src/app/app.component.css create mode 100644 public/docs/_examples/template-syntax/ts/src/app/hero-form.component.html create mode 100644 public/docs/_examples/template-syntax/ts/src/app/hero-form.component.ts create mode 100644 public/docs/_examples/template-syntax/ts/src/app/hero-switch.components.ts create mode 100644 public/docs/ts/latest/guide/ngcontainer.jade create mode 100644 public/resources/images/devguide/ngcontainer/hero-traits-bad.png create mode 100644 public/resources/images/devguide/ngcontainer/hero-traits-good.png create mode 100644 public/resources/images/devguide/structural-directives/bad-paragraph.png create mode 100644 public/resources/images/devguide/structural-directives/bad-select.png create mode 100644 public/resources/images/devguide/structural-directives/element-display-in-dom.png create mode 100644 public/resources/images/devguide/structural-directives/good-paragraph.png delete mode 100644 public/resources/images/devguide/structural-directives/heavy-loader-toggle.gif create mode 100644 public/resources/images/devguide/structural-directives/hero-div-in-dom.png create mode 100644 public/resources/images/devguide/structural-directives/ngSwitch-rendering.png create mode 100644 public/resources/images/devguide/structural-directives/select-ngcontainer-anim.gif delete mode 100644 public/resources/images/devguide/structural-directives/template-in-out-of-a2.png create mode 100644 public/resources/images/devguide/structural-directives/template-rendering.png create mode 100644 public/resources/images/devguide/structural-directives/unless-anim.gif delete mode 100644 public/resources/images/devguide/template-syntax/ng-switch-anim.gif create mode 100644 public/resources/images/devguide/template-syntax/switch-anim.gif diff --git a/public/docs/_examples/ngcontainer/ts/example-config.json b/public/docs/_examples/ngcontainer/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/ngcontainer/ts/plnkr.json b/public/docs/_examples/ngcontainer/ts/plnkr.json new file mode 100644 index 0000000000..a6cdc4ba1a --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/plnkr.json @@ -0,0 +1,11 @@ +{ + "description": "", + "basePath": "src/", + "files": [ + "!**/*.d.ts", + "!**/*.js" + ], + "tags": [ + "ngcontainer", "structural", "directives" + ] +} diff --git a/public/docs/_examples/ngcontainer/ts/src/app/app.component.css b/public/docs/_examples/ngcontainer/ts/src/app/app.component.css new file mode 100644 index 0000000000..953ed3c39d --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/app.component.css @@ -0,0 +1,34 @@ +/* #docregion */ +button { + min-width: 100px; + font-size: 100%; +} + +code, .code { + background-color: #eee; + color: black; + font-family: Courier, sans-serif; + font-size: 85%; +} + +div.code { + width: 400px; +} + +.heroic { + font-size: 150%; + font-weight: bold; +} + +hr { + margin: 40px 0 +} + +td, th { + text-align: left; + vertical-align: top; +} + +/* #docregion p-span */ +p span { color: red; font-size: 70%; } +/* #enddocregion p-span */ diff --git a/public/docs/_examples/ngcontainer/ts/src/app/app.component.html b/public/docs/_examples/ngcontainer/ts/src/app/app.component.html new file mode 100644 index 0000000000..afd0b00f36 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/app.component.html @@ -0,0 +1,279 @@ + + +

<ng-container>

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

<ng-container> and CSS

+

Examples demonstrating issues with rigid CSS styles.

+ + + +

#1 <ng-container> and <p>

+ +

+ I turned the corner + + and saw {{hero.name}}. I waved + + and continued on my way. +

+ + +

+ I turned the corner + + and saw {{hero.name}}. I waved + + and continued on my way. +

+ + +

#2 <ng-container> and <p>

+ +
+ +

+ {{hero.name}} is + + , + and + {{trait}} + . +

+ + + +

+ {{hero.name}} is + + , + and + {{trait}} + . +

+ + +
+ +

#3 <ng-container> and <p>

+ +

+ +

+ + +
+ The hero.id in the <span> + is caught by the p-span CSS: + +

+ + Id: ({{hero.id}}) + + Name: {{hero.name}} +

+ +
+ +
+ The hero.id in the <ng-container> + is unaffected by the p-span CSS: +

+ + Id: ({{hero.id}}) + + Name: {{hero.name}} +

+
+ +
+ The hero.id in the <template *ngIf> disappears: +

+ + Name: {{hero.name}} +

+
+ +
+ The hero.id in the <template [ngIf]> + is unaffected by the p-span CSS: +

+ + Name: {{hero.name}} +

+
+ +
+ +
+ +

<ng-container> and layout-sensitive elements

+

+ Examples demonstrating issues with layout-sensitive elements + such as <select> and <table>. +

+ +

#1 <ng-container> and <options>

+ +

<select> with <span>

+
+ Pick your favorite hero + () +
+ + + + +

<select> with <ng-container>

+
+ Pick your favorite hero + () +
+ + + + +



+ +

#2 <ng-container> and <options>

+

+ +

+ +

Options with <ng-container>

+ + + + +

Options with <span>

+ + + + +
+ +

<ng-container> and <table>

+

+ + + +

+ + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveTypeDescription
NgClassAAdd or remove multiple CSS classes.
xxxSdiv with *ngIf formats crazy.
yyySdiv with *ngIf formats crazy.
NgForSRepeat the template for each item in a list.
NgIfSAdd or remove DOM elements.
NgStyleAAdd or remove multiple style attributes.
NgSwitchSInclude in DOM if case matches the switch value.
+ +
+ +

Do not confuse <ng-container> with <ng-content>

+ +

<ng-container>Inside ng-container</ng-container>

+ +Inside ng-container + + +

<ng-content>this is an Angular parse error</ng-content>

+ + + +
Template parse errors:
+<ng-content> element cannot have content.
+ +

Demo of </ng-content>

+ + + Projected content + + diff --git a/public/docs/_examples/ngcontainer/ts/src/app/app.component.ts b/public/docs/_examples/ngcontainer/ts/src/app/app.component.ts new file mode 100644 index 0000000000..2d6d7f959c --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/app.component.ts @@ -0,0 +1,25 @@ +// #docregion +import { Component } from '@angular/core'; + +import { heroes } from './hero'; + +@Component({ + moduleId: module.id, + selector: 'my-app', + templateUrl: './app.component.html', + styleUrls: [ './app.component.css' ] +}) +export class AppComponent { + heroes = heroes; + hero = this.heroes[0]; + heroTraits = [ 'honest', 'brave', 'considerate' ]; + + // flags for the table + attrDirs = true; + strucDirs = true; + divNgIf = false; + + showId = true; + showDefaultTraits = true; + showSad = true; +} diff --git a/public/docs/_examples/ngcontainer/ts/src/app/app.module.ts b/public/docs/_examples/ngcontainer/ts/src/app/app.module.ts new file mode 100644 index 0000000000..57ac92f518 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/app.module.ts @@ -0,0 +1,19 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { ContentComponent } from './content.component'; +import { heroComponents } from './hero.components'; + +@NgModule({ + imports: [ BrowserModule, FormsModule ], + declarations: [ + AppComponent, + ContentComponent, + heroComponents + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/ngcontainer/ts/src/app/content.component.ts b/public/docs/_examples/ngcontainer/ts/src/app/content.component.ts new file mode 100644 index 0000000000..63c5646f99 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/content.component.ts @@ -0,0 +1,16 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'content-comp', + // #docregion template + template: + `
+ +
`, + // #enddocregion template + styles: [ ` + div { border: medium dashed green; padding: 1em; width: 150px; text-align: center} + `] +}) +export class ContentComponent { } diff --git a/public/docs/_examples/ngcontainer/ts/src/app/hero.components.ts b/public/docs/_examples/ngcontainer/ts/src/app/hero.components.ts new file mode 100644 index 0000000000..43e400ed8e --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/hero.components.ts @@ -0,0 +1,43 @@ +// #docregion +import { Component, Input } from '@angular/core'; +import { Hero } from './hero'; + +@Component({ + selector: 'happy-hero', + template: `Wow. You like {{hero.name}}. What a happy hero ... just like you.` +}) +export class HappyHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'sad-hero', + template: `You like {{hero.name}}? Such a sad hero. Are you sad too?` +}) +export class SadHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'confused-hero', + template: `Are you as confused as {{hero.name}}?` +}) +export class ConfusedHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'unknown-hero', + template: `{{message}}` +}) +export class UnknownHeroComponent { + @Input() hero: Hero; + get message() { + return this.hero && this.hero.name ? + `${this.hero.name} is strange and mysterious.` : + 'Are you feeling indecisive?'; + } +} + +export const heroComponents = + [ HappyHeroComponent, SadHeroComponent, ConfusedHeroComponent, UnknownHeroComponent ]; diff --git a/public/docs/_examples/ngcontainer/ts/src/app/hero.ts b/public/docs/_examples/ngcontainer/ts/src/app/hero.ts new file mode 100644 index 0000000000..a1de3b3b82 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/hero.ts @@ -0,0 +1,13 @@ +// #docregion +export class Hero { + id: number; + name: string; + emotion?: string; +} + +export const heroes: Hero[] = [ + { id: 1, name: 'Mr. Nice', emotion: 'happy'}, + { id: 2, name: 'Narco', emotion: 'sad' }, + { id: 3, name: 'Windstorm', emotion: 'confused' }, + { id: 4, name: 'Magneta'} +]; diff --git a/public/docs/_examples/ngcontainer/ts/src/index.html b/public/docs/_examples/ngcontainer/ts/src/index.html new file mode 100644 index 0000000000..fc5ff417c3 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/index.html @@ -0,0 +1,26 @@ + + + + + Angular <ng-container> + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/ngcontainer/ts/src/main.ts b/public/docs/_examples/ngcontainer/ts/src/main.ts new file mode 100644 index 0000000000..105b06712d --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); + diff --git a/public/docs/_examples/structural-directives/e2e-spec.ts b/public/docs/_examples/structural-directives/e2e-spec.ts index 335915eb86..51f30bf0bb 100644 --- a/public/docs/_examples/structural-directives/e2e-spec.ts +++ b/public/docs/_examples/structural-directives/e2e-spec.ts @@ -1,68 +1,58 @@ -'use strict'; // necessary for es6 output in node +'use strict'; // necessary for es6 output in node import { browser, element, by } from 'protractor'; describe('Structural Directives', function () { - // tests interact - so we need beforeEach instead of beforeAll - beforeEach(function () { + beforeAll(function () { browser.get(''); }); - it('should be able to use ngFor, ngIf and ngWhen together', function () { - let allDivEles = element.all(by.css('structural-directives > div')); - expect(allDivEles.get(0).getText()).toEqual('Mr. Nice'); - expect(allDivEles.get(1).getText()).toEqual('Mr. Nice'); - expect(allDivEles.get(4).getText()).toEqual('Ready'); + it('first div should show hero name with *ngIf', function () { + const allDivs = element.all(by.tagName('div')); + expect(allDivs.get(0).getText()).toEqual('Mr. Nice'); }); - it('should be able to toggle ngIf with a button', function () { - let setConditionButtonEle = element.all(by.css('button')).get(0); - let conditionTrueEles = element.all(by.cssContainingText('p', 'condition is true')); - let conditionFalseEles = element.all(by.cssContainingText('p', 'condition is false')); - expect(conditionTrueEles.count()).toBe(2, 'should be two condition true elements'); - expect(conditionFalseEles.count()).toBe(0, 'should be no condition false elements'); - setConditionButtonEle.click().then(function() { - expect(conditionTrueEles.count()).toBe(0, 'should be no condition true elements'); - expect(conditionFalseEles.count()).toBe(2, 'should be two condition false elements'); + it('first li should show hero name with *ngFor', function () { + const allLis = element.all(by.tagName('li')); + expect(allLis.get(0).getText()).toEqual('Mr. Nice'); + }); + + it('ngSwitch have three instances', function () { + const happyHeroEls = element.all(by.tagName('happy-hero')); + expect(happyHeroEls.count()).toEqual(3); + }); + + it('should toggle *ngIf="hero" with a button', function () { + const toggleHeroButton = element.all(by.cssContainingText('button', 'Toggle hero')).get(0); + const paragraph = element.all(by.cssContainingText('p', 'I turned the corner')); + expect(paragraph.get(0).getText()).toContain('I waved'); + toggleHeroButton.click().then(() => { + expect(paragraph.get(0).getText()).not.toContain('I waved'); }); }); - it('should be able to compare use of ngIf with changing css visibility', function () { - let setConditionButtonEle = element.all(by.css('button')).get(0); - let ngIfButtonEle = element(by.cssContainingText('button', 'if | !if')); - let ngIfParentEle = ngIfButtonEle.element(by.xpath('..')); - let ngIfSiblingEle = ngIfParentEle.element(by.css('heavy-loader')); - let cssButtonEle = element(by.cssContainingText('button', 'show | hide')); - let cssSiblingEle = cssButtonEle.element(by.xpath('..')).element(by.css('heavy-loader')); - let setConditionText: string; - setConditionButtonEle.getText().then(function(text: string) { - setConditionText = text; - expect(ngIfButtonEle.isPresent()).toBe(true, 'should be able to find ngIfButton'); - expect(cssButtonEle.isPresent()).toBe(true, 'should be able to find cssButton'); - expect(ngIfParentEle.isPresent()).toBe(true, 'should be able to find ngIfButton parent'); - expect(ngIfSiblingEle.isPresent()).toBe(true, 'should be able to find ngIfButton sibling'); - expect(cssSiblingEle.isPresent()).toBe(true, 'should be able to find cssButton sibling'); - return ngIfButtonEle.click(); - }).then(function() { - expect(ngIfSiblingEle.isPresent()).toBe(false, 'now should NOT be able to find ngIfButton sibling'); - expect(setConditionButtonEle.getText()).not.toEqual(setConditionText); - return cssButtonEle.click(); - }).then(function() { - expect(cssSiblingEle.isPresent()).toBe(true, 'now should still be able to find cssButton sibling'); - expect(cssSiblingEle.isDisplayed()).toBe(false, 'now cssButton sibling should NOT be visible'); - return ngIfButtonEle.click(); - }).then(function() { - expect(setConditionButtonEle.getText()).toEqual(setConditionText); - }); + it('should have only one "Hip!" (the other is erased)', function () { + const paragraph = element.all(by.cssContainingText('p', 'Hip!')); + expect(paragraph.count()).toEqual(1); }); - it('should be able to use *ngIf ', function () { - let setConditionButtonEle = element.all(by.css('button')).get(0); - let displayEles = element.all(by.cssContainingText('p', 'Our heroes are true!')); - expect(displayEles.count()).toBe(2, 'should be displaying two ngIf elements'); - setConditionButtonEle.click().then(function() { - expect(displayEles.count()).toBe(0, 'should nog longer be displaying ngIf elements'); + it('myUnless should show 3 paragraph (A)s and (B)s at the start', function () { + const paragraph = element.all(by.css('p.unless')); + expect(paragraph.count()).toEqual(3); + for (let i = 0; i < 3; i++) { + expect(paragraph.get(i).getText()).toContain('(A)'); + } + }); + + it('myUnless should show 1 paragraph (B) after toggling condition', function () { + const toggleConditionButton = element.all(by.cssContainingText('button', 'Toggle condition')).get(0); + const paragraph = element.all(by.css('p.unless')); + + toggleConditionButton.click().then(() => { + expect(paragraph.count()).toEqual(1); + expect(paragraph.get(0).getText()).toContain('(B)'); }); }); }); + diff --git a/public/docs/_examples/structural-directives/ts/plnkr.json b/public/docs/_examples/structural-directives/ts/plnkr.json index 9aa0a3ed8a..58a26d7b4f 100644 --- a/public/docs/_examples/structural-directives/ts/plnkr.json +++ b/public/docs/_examples/structural-directives/ts/plnkr.json @@ -1,7 +1,11 @@ { "description": "Structural directives", "basePath": "src/", - "files": ["!**/*.d.ts", "!**/*.js"], + "files": [ + "!**/*.d.ts", + "!**/*.js", + "!app/scrap.txt" + ], "tags": [ "structural", "directives", "template", "ngIf", "ngSwitch", "ngFor" diff --git a/public/docs/_examples/structural-directives/ts/src/app/app.component.css b/public/docs/_examples/structural-directives/ts/src/app/app.component.css new file mode 100644 index 0000000000..e28be894f8 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/app.component.css @@ -0,0 +1,70 @@ +/* #docregion */ +button { + min-width: 100px; + font-size: 100%; +} + +.box { + border: 1px solid gray; + max-width: 600px; + padding: 4px; +} +.choices { + font-style: italic; +} + +code, .code { + background-color: #eee; + color: black; + font-family: Courier, sans-serif; + font-size: 85%; +} + +div.code { + width: 400px; +} + +.heroic { + font-size: 150%; + font-weight: bold; +} + +hr { + margin: 40px 0 +} + +.odd { + background-color: palegoldenrod; +} + +td, th { + text-align: left; + vertical-align: top; +} + +/* #docregion p-span */ +p span { color: red; font-size: 70%; } +/* #enddocregion p-span */ + +.unless { + border: 2px solid; + padding: 6px; +} + +p.unless { + width: 500px; +} + +button.a, span.a, .unless.a { + color: red; + border-color: gold; + background-color: yellow; + font-size: 100%; +} + +button.b, span.b, .unless.b { + color: black; + border-color: green; + background-color: lightgreen; + font-size: 100%; +} diff --git a/public/docs/_examples/structural-directives/ts/src/app/app.component.html b/public/docs/_examples/structural-directives/ts/src/app/app.component.html new file mode 100644 index 0000000000..2758553e39 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/app.component.html @@ -0,0 +1,252 @@ + + +

Structural Directives

+ +

Conditional display of hero

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

List of heroes

+ + +
    + +
  • {{hero.name}}
  • + +
+ + + +
+ +

NgIf

+ + +

+ Expression is true and ngIf is true. + This paragraph is in the DOM. +

+

+ Expression is false and ngIf is false. + This paragraph is not in the DOM. +

+ + + +

+ Expression sets display to "block"" . + This paragraph is visible. +

+

+ Expression sets display to "none" . + This paragraph is hidden but still in the DOM. +

+ + +

NgIf with template

+

<template> element

+ + + + +

template attribute

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

<ng-container>

+ +

*ngIf with a <ng-container>

+ + + + +

+ I turned the corner + + and saw {{hero.name}}. I waved + + and continued on my way. +

+ + +

+ I turned the corner + + and saw {{hero.name}}. I waved + + and continued on my way. +

+ + +

<select> with <span>

+ +
+ Pick your favorite hero + () +
+ + + +

<select> with <ng-container>

+ +
+ Pick your favorite hero + () +
+ + +

+ +
+ +

NgFor

+ +
+ +

<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">

+ +
+ ({{i}}) {{hero.name}} +
+ + +

<div template="ngFor let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">

+ +
+ ({{i}}) {{hero.name}} +
+ + +

<template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">

+ + + + +
+
+ +

NgSwitch

+ +
Pick your favorite hero
+

+ + + + +

+ +

NgSwitch

+ + +
+ + + + +
+ + +

NgSwitch with template attribute

+ +
+ + + + +
+ + +

NgSwitch with <template>

+ +
+ + + + +
+ + +
+ +

<template>

+ +

Hip!

+ +

Hooray!

+ + +
+ +

UnlessDirective

+

+ The condition is currently + {{condition}}. + +

+ +

+ (A) This paragraph is displayed because the condition is false. +

+ +

+ (B) Although the condition is true, + this paragraph is displayed because myUnless is set to false. +

+ + + +

UnlessDirective with template

+ + +

Show this sentence unless the condition is true.

+ + +

+ (A) <p template="myUnless condition" class="code unless"> +

+ + + diff --git a/public/docs/_examples/structural-directives/ts/src/app/app.component.ts b/public/docs/_examples/structural-directives/ts/src/app/app.component.ts new file mode 100644 index 0000000000..5fd9dc417f --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/app.component.ts @@ -0,0 +1,24 @@ +// #docregion +import { Component } from '@angular/core'; + +import { Hero, heroes } from './hero'; + +@Component({ + moduleId: module.id, + selector: 'my-app', + templateUrl: './app.component.html', + styleUrls: [ './app.component.css' ] +}) +export class AppComponent { + heroes = heroes; + hero = this.heroes[0]; + + condition = false; + logs: string[] = []; + showSad = true; + status = 'ready'; + + // #docregion trackByHero + trackById(index: number, hero: Hero): number { return hero.id; } + // #enddocregion trackByHero +} diff --git a/public/docs/_examples/structural-directives/ts/src/app/app.module.ts b/public/docs/_examples/structural-directives/ts/src/app/app.module.ts index 0712db6d4b..b6ffb456c9 100644 --- a/public/docs/_examples/structural-directives/ts/src/app/app.module.ts +++ b/public/docs/_examples/structural-directives/ts/src/app/app.module.ts @@ -1,18 +1,19 @@ // #docregion -import { NgModule } from '@angular/core'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; -import { StructuralDirectivesComponent } from './structural-directives.component'; -import { UnlessDirective } from './unless.directive'; -import { HeavyLoaderComponent } from './heavy-loader.component'; +import { AppComponent } from './app.component'; +import { heroSwitchComponents } from './hero-switch.components'; +import { UnlessDirective } from './unless.directive'; @NgModule({ - imports: [ BrowserModule ], + imports: [ BrowserModule, FormsModule ], declarations: [ - StructuralDirectivesComponent, - UnlessDirective, - HeavyLoaderComponent + AppComponent, + heroSwitchComponents, + UnlessDirective ], - bootstrap: [ StructuralDirectivesComponent ] + bootstrap: [ AppComponent ] }) export class AppModule { } diff --git a/public/docs/_examples/structural-directives/ts/src/app/heavy-loader.component.ts b/public/docs/_examples/structural-directives/ts/src/app/heavy-loader.component.ts deleted file mode 100644 index 6eaa9309e8..0000000000 --- a/public/docs/_examples/structural-directives/ts/src/app/heavy-loader.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -// #docregion -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; - -let nextId = 1; - -@Component({ - selector: 'heavy-loader', - template: 'heavy loader #{{id}} on duty!' -}) -export class HeavyLoaderComponent implements OnDestroy, OnInit { - id = nextId++; - @Input() logs: string[]; - - ngOnInit() { - // Mock todo: get 10,000 rows of data from the server - this.log(`heavy-loader ${this.id} initialized, - loading 10,000 rows of data from the server`); - } - - ngOnDestroy() { - // Mock todo: clean-up - this.log(`heavy-loader ${this.id} destroyed, cleaning up`); - } - - private log(msg: string) { - this.logs.push(msg); - this.tick(); - } - - // Triggers the next round of Angular change detection - // after one turn of the browser event loop - // ensuring display of msg added in onDestroy - private tick() { setTimeout(() => { }, 0); } -} -// #enddocregion diff --git a/public/docs/_examples/structural-directives/ts/src/app/hero-switch.components.ts b/public/docs/_examples/structural-directives/ts/src/app/hero-switch.components.ts new file mode 100644 index 0000000000..6608422d15 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/hero-switch.components.ts @@ -0,0 +1,43 @@ +// #docregion +import { Component, Input } from '@angular/core'; +import { Hero } from './hero'; + +@Component({ + selector: 'happy-hero', + template: `Wow. You like {{hero.name}}. What a happy hero ... just like you.` +}) +export class HappyHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'sad-hero', + template: `You like {{hero.name}}? Such a sad hero. Are you sad too?` +}) +export class SadHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'confused-hero', + template: `Are you as confused as {{hero.name}}?` +}) +export class ConfusedHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'unknown-hero', + template: `{{message}}` +}) +export class UnknownHeroComponent { + @Input() hero: Hero; + get message() { + return this.hero && this.hero.name ? + `${this.hero.name} is strange and mysterious.` : + 'Are you feeling indecisive?'; + } +} + +export const heroSwitchComponents = + [ HappyHeroComponent, SadHeroComponent, ConfusedHeroComponent, UnknownHeroComponent ]; diff --git a/public/docs/_examples/structural-directives/ts/src/app/hero.ts b/public/docs/_examples/structural-directives/ts/src/app/hero.ts new file mode 100644 index 0000000000..a1de3b3b82 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/hero.ts @@ -0,0 +1,13 @@ +// #docregion +export class Hero { + id: number; + name: string; + emotion?: string; +} + +export const heroes: Hero[] = [ + { id: 1, name: 'Mr. Nice', emotion: 'happy'}, + { id: 2, name: 'Narco', emotion: 'sad' }, + { id: 3, name: 'Windstorm', emotion: 'confused' }, + { id: 4, name: 'Magneta'} +]; diff --git a/public/docs/_examples/structural-directives/ts/src/app/scrap.txt b/public/docs/_examples/structural-directives/ts/src/app/scrap.txt new file mode 100644 index 0000000000..96426d37f0 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/scrap.txt @@ -0,0 +1,21 @@ +// interesting but unused code + heroChooser(picker: HTMLFieldSetElement) { + let choices = picker.children; + this.favoriteHero = undefined; + for (let i = 0; i < choices.length; i++) { + let choice = choices[i].children[0] as HTMLInputElement; + if (choice.checked) { this.favoriteHero = this.heroes[i]; } + } + } + + +

Switch with *ngFor repeated switchCases using <ng-container>

+ +
+ Your favorite hero is ... + + {{hero.name}} + + None of the above +
+ diff --git a/public/docs/_examples/structural-directives/ts/src/app/structural-directives.component.html b/public/docs/_examples/structural-directives/ts/src/app/structural-directives.component.html deleted file mode 100644 index cf19ebb137..0000000000 --- a/public/docs/_examples/structural-directives/ts/src/app/structural-directives.component.html +++ /dev/null @@ -1,109 +0,0 @@ - - -

Structural Directives

- - - -
{{hero}}
-
{{hero}}
- - -
- - - -
- - - -
- - - - -

- condition is true and ngIf is true. -

-

- condition is false and ngIf is false. -

- - -

- condition is false and myUnless is true. -

- -

- condition is true and myUnless is false. -

- - -
- - -
- - -
- -
- - -
- -

heavy-loader log:

-
{{message}}
- - -
- - -

- Hip! -

- -

- Hooray! -

- - -
- - - - -

- Our heroes are true! -

- - - - - -
- - - - - -
{{ hero }}
- - - - - diff --git a/public/docs/_examples/structural-directives/ts/src/app/structural-directives.component.ts b/public/docs/_examples/structural-directives/ts/src/app/structural-directives.component.ts deleted file mode 100644 index 1c073c74e1..0000000000 --- a/public/docs/_examples/structural-directives/ts/src/app/structural-directives.component.ts +++ /dev/null @@ -1,19 +0,0 @@ -// #docplaster -// #docregion -import { Component } from '@angular/core'; - -@Component({ - moduleId: module.id, - selector: 'structural-directives', - templateUrl: './structural-directives.component.html', - styles: ['button { min-width: 100px; }'] -}) -export class StructuralDirectivesComponent { - heroes = ['Mr. Nice', 'Narco', 'Bombasto']; - hero = this.heroes[0]; - condition = true; - isVisible = true; - logs: string[] = []; - status = 'ready'; -} -// #enddocregion diff --git a/public/docs/_examples/structural-directives/ts/src/app/unless.directive.ts b/public/docs/_examples/structural-directives/ts/src/app/unless.directive.ts index 105fdde4ae..19d48b4453 100644 --- a/public/docs/_examples/structural-directives/ts/src/app/unless.directive.ts +++ b/public/docs/_examples/structural-directives/ts/src/app/unless.directive.ts @@ -1,33 +1,55 @@ // #docplaster // #docregion -// #docregion unless-declaration -import { Directive, Input } from '@angular/core'; +// #docregion no-docs +// #docregion skeleton +import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core'; -// #enddocregion unless-declaration -import { TemplateRef, ViewContainerRef } from '@angular/core'; - -// #docregion unless-declaration -@Directive({ selector: '[myUnless]' }) +// #enddocregion skeleton +/** + * Add the template content to the DOM unless the condition is true. +// #enddocregion no-docs + * + * If the expression assigned to `myUnless` evaluates to a truthy value + * then the templated elements are removed removed from the DOM, + * the templated elements are (re)inserted into the DOM. + * + *
+ * Congrats! Everything is great! + *
+ * + * ### Syntax + * * + * - `
...
` + * - `
...
` + * - `` + * +// #docregion no-docs + */ +// #docregion skeleton +@Directive({ selector: '[myUnless]'}) export class UnlessDirective { - // #enddocregion unless-declaration + // #enddocregion skeleton + private hasView = false; - // #docregion unless-constructor + // #docregion ctor constructor( private templateRef: TemplateRef, - private viewContainer: ViewContainerRef - ) { } - // #enddocregion unless-constructor + private viewContainer: ViewContainerRef) { } + // #enddocregion ctor - // #docregion unless-set + // #docregion set @Input() set myUnless(condition: boolean) { - if (!condition) { + if (!condition && !this.hasView) { this.viewContainer.createEmbeddedView(this.templateRef); - } else { + this.hasView = true; + } else if (condition && this.hasView) { this.viewContainer.clear(); + this.hasView = false; } } - // #enddocregion unless-set - // #docregion unless-declaration + // #enddocregion set + // #docregion skeleton } -// #enddocregion unless-declaration +// #enddocregion skeleton +// #enddocregion no-docs // #enddocregion diff --git a/public/docs/_examples/structural-directives/ts/src/index.html b/public/docs/_examples/structural-directives/ts/src/index.html index b77d172317..ce7a33266d 100644 --- a/public/docs/_examples/structural-directives/ts/src/index.html +++ b/public/docs/_examples/structural-directives/ts/src/index.html @@ -21,7 +21,7 @@ - Loading... + Loading... diff --git a/public/docs/_examples/template-syntax/ts/src/app/app.component.css b/public/docs/_examples/template-syntax/ts/src/app/app.component.css new file mode 100644 index 0000000000..23f9667623 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/app.component.css @@ -0,0 +1,17 @@ +a.to-toc { margin: 30px 0; } +button { font-size: 100%; margin: 0 2px; } +div[clickable] {cursor: pointer; max-width: 200px; margin: 16px 0} +#noTrackByCnt, #withTrackByCnt {color: darkred; max-width: 450px; margin: 4px;} +img {height: 100px;} +.box {border: 1px solid black; padding: 6px; max-width: 450px;} +.child-div {margin-left: 1em; font-weight: normal} +.context {margin-left: 1em;} +.hidden {display: none} +.parent-div {margin-top: 1em; font-weight: bold} +.special {font-weight:bold; font-size: x-large} +.bad {color: red;} +.saveable {color: limegreen;} +.curly, .modified {font-family: "Brush Script MT"} +.toe {margin-left: 1em; font-style: italic;} +little-hero {color:blue; font-size: smaller; background-color: Turquoise } +.to-toc {margin-top: 10px; display: block} diff --git a/public/docs/_examples/template-syntax/ts/src/app/app.component.html b/public/docs/_examples/template-syntax/ts/src/app/app.component.html index 66d35f5df0..b3d6c29be5 100644 --- a/public/docs/_examples/template-syntax/ts/src/app/app.component.html +++ b/public/docs/_examples/template-syntax/ts/src/app/app.component.html @@ -2,6 +2,8 @@

Template Syntax

Interpolation
+Expression context
+Statement context
Mental Model
Buttons
Properties vs. Attributes
@@ -22,15 +24,14 @@ NgClass Binding
NgStyle Binding
NgIf
- NgSwitch
NgFor
+ NgSwitch

-* prefix and <template>
Template reference variables
Inputs and outputs
Pipes
@@ -41,7 +42,7 @@

Interpolation

-

My current hero is {{currentHero.firstName}}

+

My current hero is {{currentHero.name}}

@@ -63,6 +64,68 @@ top +

Expression context

+ +

Component expression context ({{title}}, [hidden]="isUnchanged")

+
+ + {{title}} + changed + +
+ + +

Template input variable expression context (let hero)

+ + + +

Template reference variable expression context (#heroInput)

+
+ Type something: + + {{heroInput.value}} + +
+ +top + +

Statement context

+ +

Component statement context ( (click)="onSave() ) +

+ + + +
+ +

Template $event statement context

+
+ + + +
+ +

Template input variable statement context (let hero)

+ +
+ + + +
+ +

Template reference variable statement context (#heroForm)

+
+ +
...
+ +
+ +top +

New Mental Model

@@ -105,16 +168,17 @@ -
click me
+
click me
{{clicked}}

+ Hero Name: - Hero Name: {{heroName}} + {{heroName}}


@@ -205,6 +269,10 @@ button +

"{{evilTitle}}" is the interpolated evil title.

"" is the property bound evil title.

@@ -307,7 +375,7 @@ button -
click with myClick
+
click with myClick
{{clickMessage}} @@ -326,26 +394,25 @@ button -
Click me +
Click me
Click me too!
-

-
+
-

+ -
+
-

+ top

Two-way Binding

@@ -363,7 +430,6 @@ button
-

top @@ -371,38 +437,37 @@ button passing the changed display value to the event handler via `$event` -->

NgModel (two-way) Binding

-

Result: {{currentHero.firstName}}

+

Result: {{currentHero.name}}

- + without NgModel
- + [(ngModel)]
- + bindon-ngModel
+ [ngModel]="currentHero.name" + (ngModelChange)="currentHero.name=$event"> -(ngModelChange) = "...firstName=$event" +(ngModelChange) = "...name=$event"
+ [ngModel]="currentHero.name" + (ngModelChange)="setUppercaseName($event)"> -(ngModelChange) = "setUpperCaseFirstName($event)" -
+(ngModelChange) = "setUppercaseName($event)" top @@ -417,7 +482,7 @@ bindon-ngModel
| - | + |

@@ -462,7 +527,6 @@ bindon-ngModel This div should be {{ canSave ? "italic": "plain"}}, {{ isUnchanged ? "normal weight" : "bold" }} and, {{ isSpecial ? "extra large": "normal size"}} after clicking "refresh".
-
top @@ -470,21 +534,17 @@ bindon-ngModel

NgIf Binding

-
Hello, {{currentHero.firstName}}
+ - -
Hello, {{nullHero.firstName}}
- - - +
Hello, {{currentHero.name}}
+
Hello, {{nullHero.name}}
- +
Hero Detail removed from DOM (via template) because isActive is false
@@ -506,170 +566,117 @@ bindon-ngModel top - -

NgSwitch Binding

- -
- Eenie - Meanie - Miney - Moe - ??? -
- -
-
Pick a toe
-
- You picked ... - - - - - - - Eenie - Meanie - Miney - Moe - other - - - - - - - - - - - - -
-
- -top -

NgFor Binding

- -
{{hero.fullName}}
- + +
{{hero.name}}
+

- + - +
top -

NgFor with index

+

*ngFor with index

with semi-colon separator

-
{{i + 1}} - {{hero.fullName}}
+
{{i + 1}} - {{hero.name}}

with comma separator

- -
{{i + 1}} - {{hero.fullName}}
+ +
{{i + 1}} - {{hero.name}}
top -

NgForTrackBy

- -

First hero:

+

*ngFor trackBy

+ + +

without trackBy

-
- -
({{hero.id}}) {{hero.fullName}}
- -
-
- Hero DOM elements change #{{heroesNoTrackByChangeCount}} without trackBy +
+
({{hero.id}}) {{hero.name}}
+ +
+ Hero DOM elements change #{{heroesNoTrackByCount}} without trackBy +
-

with trackBy and semi-colon separator

-
- -
({{hero.id}}) {{hero.fullName}}
- +

with trackBy

+
+
({{hero.id}}) {{hero.name}}
+ +
+ Hero DOM elements change #{{heroesWithTrackByCount}} with trackBy +
-
- Hero DOM elements change #{{heroesWithTrackByChangeCount}} with trackBy + +


+ +

with trackBy and semi-colon separator

+
+ +
+ ({{hero.id}}) {{hero.name}} +
+

with trackBy and comma separator

-
({{hero.id}}) {{hero.fullName}}
+
({{hero.id}}) {{hero.name}}

with trackBy and space separator

-
({{hero.id}}) {{hero.fullName}}
+
({{hero.id}}) {{hero.name}}

with generic trackById function

-
({{hero.id}}) {{hero.fullName}}
+
({{hero.id}}) {{hero.name}}
top - -

* prefix and <template>

+ +

NgSwitch Binding

-

*ngIf expansion

-

*ngIf

- - - +
Pick your favorite hero
+

+ + + +

-

expand to template = "..."

- - - - -

expand to <template>

- - - - -

*ngFor expansion

-

*ngFor

- - - - - -

expand to template = "..."

-
- - - - -
- -

expand to <template>

-
- - - - + +
+ + + + + +
Are you as confused as {{currentHero.name}}?
+ + +
+ top @@ -677,34 +684,27 @@ bindon-ngModel

Template reference variables

- + - + - - - + + + + -

Example Form

- - -
- -
- - -
- - -
- - -

+ + + + +

Example Form

+ + top @@ -720,7 +720,7 @@ bindon-ngModel -
myClick2
+
myClick2
{{clickMessage2}} top @@ -769,43 +769,42 @@ bindon-ngModel
- The current hero's name is {{currentHero?.firstName}} + The current hero's name is {{currentHero?.name}}
- The current hero's name is {{currentHero.firstName}} + The current hero's name is {{currentHero.name}}
-
The null hero's name is {{nullHero.firstName}}
+
The null hero's name is {{nullHero.name}}
-The null hero's name is {{nullHero && nullHero.firstName}} +The null hero's name is {{nullHero && nullHero.name}}
- The null hero's name is {{nullHero?.firstName}} + The null hero's name is {{nullHero?.name}}
- top diff --git a/public/docs/_examples/template-syntax/ts/src/app/app.component.ts b/public/docs/_examples/template-syntax/ts/src/app/app.component.ts index eb9b27ca52..166948362f 100644 --- a/public/docs/_examples/template-syntax/ts/src/app/app.component.ts +++ b/public/docs/_examples/template-syntax/ts/src/app/app.component.ts @@ -2,7 +2,6 @@ // #docplaster import { AfterViewInit, Component, ElementRef, OnInit, QueryList, ViewChildren } from '@angular/core'; -import { NgForm } from '@angular/forms'; import { Hero } from './hero'; @@ -19,20 +18,26 @@ export enum Color {Red, Green, Blue}; @Component({ moduleId: module.id, selector: 'my-app', - templateUrl: './app.component.html' + templateUrl: './app.component.html', + styleUrls: [ './app.component.css' ] }) export class AppComponent implements AfterViewInit, OnInit { ngOnInit() { - this.refreshHeroes(); + this.resetHeroes(); this.setCurrentClasses(); this.setCurrentStyles(); } ngAfterViewInit() { - this.detectNgForTrackByEffects(); + // Detect effects of NgForTrackBy + trackChanges(this.heroesNoTrackBy, () => this.heroesNoTrackByCount += 1); + trackChanges(this.heroesWithTrackBy, () => this.heroesWithTrackByCount += 1); } + @ViewChildren('noTrackBy') heroesNoTrackBy: QueryList; + @ViewChildren('withTrackBy') heroesWithTrackBy: QueryList; + actionName = 'Go for it'; alert = alerter; badCurly = 'bad curly'; @@ -42,20 +47,40 @@ export class AppComponent implements AfterViewInit, OnInit { callPhone(value: string) {this.alert(`Calling ${value} ...`); } canSave = true; + changeIds() { + this.resetHeroes(); + this.heroes.forEach(h => h.id += 10 * this.heroIdIncrement++); + this.heroesWithTrackByCountReset = -1; + } + + clearTrackByCounts() { + const trackByCountReset = this.heroesWithTrackByCountReset; + this.resetHeroes(); + this.heroesNoTrackByCount = -1; + this.heroesWithTrackByCount = trackByCountReset; + this.heroIdIncrement = 1; + } + + clicked = ''; + clickMessage = ''; + clickMessage2 = ''; + Color = Color; color = Color.Red; colorToggle() {this.color = (this.color === Color.Red) ? Color.Blue : Color.Red; } - currentHero = Hero.MockHeroes[0]; + currentHero: Hero; deleteHero(hero: Hero) { - this.alert('Deleted hero: ' + (hero && hero.firstName)); + this.alert(`Delete ${hero ? hero.name : 'the hero'}.`); } // #docregion evil-title evilTitle = 'Template Syntax'; // #enddocregion evil-title + fontSizePx = 16; + title = 'Template Syntax'; getStyles(el: Element) { @@ -69,22 +94,26 @@ export class AppComponent implements AfterViewInit, OnInit { getVal() { return this.val; } + hero: Hero; // defined to demonstrate template context precedence heroes: Hero[]; + // trackBy change counting + heroesNoTrackByCount = 0; + heroesWithTrackByCount = 0; + heroesWithTrackByCountReset = 0; + + heroIdIncrement = 1; + // heroImageUrl = 'http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png'; // Public Domain terms of use: http://www.wpclipart.com/terms.html heroImageUrl = 'images/hero.png'; - // iconUrl = 'https://angular.io/resources/images/logos/standard/shield-large.png'; - clicked = ''; - clickMessage = ''; - clickMessage2 = ''; iconUrl = 'images/ng-logo.png'; isActive = false; isSpecial = true; isUnchanged = true; - nullHero: Hero = null; // or undefined + nullHero: Hero = null; onCancel(event: KeyboardEvent) { let evtMsg = event ? ' Event target is ' + (event.target).innerHTML : ''; @@ -101,26 +130,20 @@ export class AppComponent implements AfterViewInit, OnInit { this.alert('Saved.' + evtMsg); } - onSubmit(form: NgForm) { - let evtMsg = form.valid ? - ' Form value is ' + JSON.stringify(form.value) : - ' Form is invalid'; - this.alert('Form submitted.' + evtMsg); - } + onSubmit() { /* referenced but not used */} product = { name: 'frimfram', price: 42 }; - // #docregion refresh-heroes - // update this.heroes with fresh set of cloned heroes - refreshHeroes() { - this.heroes = Hero.MockHeroes.map(hero => Hero.clone(hero)); + // updates with fresh set of cloned heroes + resetHeroes() { + this.heroes = Hero.heroes.map(hero => hero.clone()); + this.currentHero = this.heroes[0]; + this.heroesWithTrackByCountReset = 0; } - // #enddocregion refresh-heroes - // #docregion same-as-it-ever-was private samenessCount = 5; moreOfTheSame() { this.samenessCount++; }; get sameAsItEverWas() { @@ -131,11 +154,9 @@ export class AppComponent implements AfterViewInit, OnInit { // return {id:id, text: 'same as it ever was ...'}; // }); } - // #enddocregion same-as-it-ever-was - setUpperCaseFirstName(firstName: string) { - // console.log(firstName); - this.currentHero.firstName = firstName.toUpperCase(); + setUppercaseName(name: string) { + this.currentHero.name = name.toUpperCase(); } // #docregion setClasses @@ -162,69 +183,31 @@ export class AppComponent implements AfterViewInit, OnInit { } // #enddocregion setStyles - toeChoice = ''; - toeChooser(picker: HTMLFieldSetElement) { - let choices = picker.children; - for (let i = 0; i < choices.length; i++) { - let choice = choices[i]; - if (choice.checked) {return this.toeChoice = choice.value; } - } - } - // #docregion trackByHeroes - trackByHeroes(index: number, hero: Hero) { return hero.id; } + trackByHeroes(index: number, hero: Hero): number { return hero.id; } // #enddocregion trackByHeroes // #docregion trackById - trackById(index: number, item: any): string { return item['id']; } + trackById(index: number, item: any): number { return item['id']; } // #enddocregion trackById val = 2; // villainImageUrl = 'http://www.clker.com/cliparts/u/s/y/L/x/9/villain-man-hi.png' // Public Domain terms of use http://www.clker.com/disclaimer.html villainImageUrl = 'images/villain.png'; - - - //////// Detect effects of NgForTrackBy /////////////// - @ViewChildren('noTrackBy') childrenNoTrackBy: QueryList; - @ViewChildren('withTrackBy') childrenWithTrackBy: QueryList; - - private _oldNoTrackBy: HTMLElement[]; - private _oldWithTrackBy: HTMLElement[]; - - heroesNoTrackByChangeCount = 0; - heroesWithTrackByChangeCount = 0; - - private detectNgForTrackByEffects() { - this._oldNoTrackBy = toArray(this.childrenNoTrackBy); - this._oldWithTrackBy = toArray(this.childrenWithTrackBy); - - this.childrenNoTrackBy.changes.subscribe((changes: any) => { - let newNoTrackBy = toArray(changes); - let isSame = this._oldNoTrackBy.every((v: any, i: number) => v === newNoTrackBy[i]); - if (!isSame) { - this._oldNoTrackBy = newNoTrackBy; - this.heroesNoTrackByChangeCount++; - } - }); - - this.childrenWithTrackBy.changes.subscribe((changes: any) => { - let newWithTrackBy = toArray(changes); - let isSame = this._oldWithTrackBy.every((v: any, i: number) => v === newWithTrackBy[i]); - if (!isSame) { - this._oldWithTrackBy = newWithTrackBy; - this.heroesWithTrackByChangeCount++; - } - }); - } - /////////////////// - } -// helper to convert viewChildren to an array of HTMLElements -function toArray(viewChildren: QueryList) { - let result: HTMLElement[] = []; - let children = viewChildren.toArray()[0].nativeElement.children; - for (let i = 0; i < children.length; i++) { result.push(children[i]); } - return result; +// helper to track changes to viewChildren +function trackChanges(views: QueryList, changed: () => void) { + let oldRefs = views.toArray(); + views.changes.subscribe((changes: QueryList) => { + const changedRefs = changes.toArray(); + // Is every changed ElemRef the same as old and in the same position + const isSame = oldRefs.every((v, i) => v === changedRefs[i]); + if (!isSame) { + oldRefs = changedRefs; + // wait a tick because called after views are constructed + setTimeout(changed, 0); + } + }); } diff --git a/public/docs/_examples/template-syntax/ts/src/app/app.module.1.ts b/public/docs/_examples/template-syntax/ts/src/app/app.module.1.ts index 47007ecae4..8ea0d3d207 100644 --- a/public/docs/_examples/template-syntax/ts/src/app/app.module.1.ts +++ b/public/docs/_examples/template-syntax/ts/src/app/app.module.1.ts @@ -1,18 +1,15 @@ // #docregion import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; +import { FormsModule } from '@angular/forms'; // <--- JavaScript import from Angular -import { AppComponent } from './app.component'; +/* Other imports */ @NgModule({ imports: [ BrowserModule, - FormsModule + FormsModule // <--- import into the NgModule ], - declarations: [ - AppComponent - ], - bootstrap: [ AppComponent ] + /* Other module metadata */ }) export class AppModule { } diff --git a/public/docs/_examples/template-syntax/ts/src/app/app.module.ts b/public/docs/_examples/template-syntax/ts/src/app/app.module.ts index 712b613daf..5c2fbed6f1 100644 --- a/public/docs/_examples/template-syntax/ts/src/app/app.module.ts +++ b/public/docs/_examples/template-syntax/ts/src/app/app.module.ts @@ -1,11 +1,13 @@ -import { NgModule } from '@angular/core'; +import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; +import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { BigHeroDetailComponent, HeroDetailComponent } from './hero-detail.component'; import { ClickDirective, ClickDirective2 } from './click.directive'; -import { SizerComponent } from './sizer.component'; +import { HeroFormComponent } from './hero-form.component'; +import { heroSwitchComponents } from './hero-switch.components'; +import { SizerComponent } from './sizer.component'; @NgModule({ imports: [ @@ -16,6 +18,8 @@ import { SizerComponent } from './sizer.component'; AppComponent, BigHeroDetailComponent, HeroDetailComponent, + HeroFormComponent, + heroSwitchComponents, ClickDirective, ClickDirective2, SizerComponent diff --git a/public/docs/_examples/template-syntax/ts/src/app/hero-detail.component.ts b/public/docs/_examples/template-syntax/ts/src/app/hero-detail.component.ts index a359a08d1c..486e6ac370 100644 --- a/public/docs/_examples/template-syntax/ts/src/app/hero-detail.component.ts +++ b/public/docs/_examples/template-syntax/ts/src/app/hero-detail.component.ts @@ -18,7 +18,7 @@ import { Hero } from './hero';
- {{prefix}} {{hero?.fullName}} + {{prefix}} {{hero?.name}}
` @@ -27,7 +27,7 @@ import { Hero } from './hero'; }) // #enddocregion input-output-2 export class HeroDetailComponent { - hero: Hero = new Hero('', 'Zzzzzzzz'); // default sleeping hero + hero: Hero = new Hero(-1, '', 'Zzzzzzzz'); // default sleeping hero // heroImageUrl = 'http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png'; // Public Domain terms of use: http://www.wpclipart.com/terms.html heroImageUrl = 'images/hero.png'; @@ -50,18 +50,22 @@ export class HeroDetailComponent { @Component({ selector: 'big-hero-detail', template: ` -
- -
{{hero?.fullName}}
-
First: {{hero?.firstName}}
-
Last: {{hero?.lastName}}
+
+ +
{{hero?.name}}
+
Name: {{hero?.name}}
+
Emotion: {{hero?.emotion}}
Birthdate: {{hero?.birthdate | date:'longDate'}}
Rate/hr: {{hero?.rate | currency:'EUR'}}

- ` + `, + styles: [` + .detail { border: 1px solid black; padding: 4px; max-width: 450px; } + img { float: left; margin-right: 8px; height: 100px; } + `] }) export class BigHeroDetailComponent extends HeroDetailComponent { diff --git a/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.html b/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.html new file mode 100644 index 0000000000..bbd417e304 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.html @@ -0,0 +1,16 @@ +
+ +
+
+ +
+ +
+
+ {{submitMessage}} +
+ +
+ diff --git a/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.ts b/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.ts new file mode 100644 index 0000000000..9a27902e1e --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.ts @@ -0,0 +1,31 @@ +import { Component, Input, ViewChild } from '@angular/core'; +import { NgForm } from '@angular/forms'; + +import { Hero } from './hero'; + +@Component({ + moduleId: module.id, + selector: 'hero-form', + templateUrl: './hero-form.component.html', + styles: [` + button { margin: 6px 0; } + #heroForm { border: 1px solid black; margin: 20px 0; padding: 8px; max-width: 350px; } + `] +}) +export class HeroFormComponent { + @Input() hero: Hero; + @ViewChild('heroForm') form: NgForm; + + private _submitMessage = ''; + + get submitMessage() { + if (!this.form.valid) { + this._submitMessage = ''; + } + return this._submitMessage; + } + + onSubmit(form: NgForm) { + this._submitMessage = 'Submitted. form value is ' + JSON.stringify(form.value); + } +} diff --git a/public/docs/_examples/template-syntax/ts/src/app/hero-switch.components.ts b/public/docs/_examples/template-syntax/ts/src/app/hero-switch.components.ts new file mode 100644 index 0000000000..a21892e248 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/hero-switch.components.ts @@ -0,0 +1,42 @@ +import { Component, Input } from '@angular/core'; +import { Hero } from './hero'; + +@Component({ + selector: 'happy-hero', + template: `Wow. You like {{hero.name}}. What a happy hero ... just like you.` +}) +export class HappyHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'sad-hero', + template: `You like {{hero.name}}? Such a sad hero. Are you sad too?` +}) +export class SadHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'confused-hero', + template: `Are you as confused as {{hero.name}}?` +}) +export class ConfusedHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'unknown-hero', + template: `{{message}}` +}) +export class UnknownHeroComponent { + @Input() hero: Hero; + get message() { + return this.hero && this.hero.name ? + `${this.hero.name} is strange and mysterious.` : + 'Are you feeling indecisive?'; + } +} + +export const heroSwitchComponents = + [ HappyHeroComponent, SadHeroComponent, ConfusedHeroComponent, UnknownHeroComponent ]; diff --git a/public/docs/_examples/template-syntax/ts/src/app/hero.ts b/public/docs/_examples/template-syntax/ts/src/app/hero.ts index ecf4d58c43..6331b62a7b 100644 --- a/public/docs/_examples/template-syntax/ts/src/app/hero.ts +++ b/public/docs/_examples/template-syntax/ts/src/app/hero.ts @@ -1,36 +1,33 @@ export class Hero { static nextId = 1; - static MockHeroes = [ + static heroes: Hero[] = [ new Hero( + 325, 'Hercules', - 'Son of Zeus', + 'happy', new Date(1970, 1, 25), - 'http://www.imdb.com/title/tt0065832/', - 325), - - new Hero('eenie', 'toe'), - new Hero('Meanie', 'Toe'), - new Hero('Miny', 'Toe'), - new Hero('Moe', 'Toe') + 'http://www.imdb.com/title/tt0065832/' + ), + new Hero(1, 'Mr. Nice', 'happy'), + new Hero(2, 'Narco', 'sad' ), + new Hero(3, 'Windstorm', 'confused' ), + new Hero(4, 'Magneta') ]; - public id: number; - - static clone({firstName, lastName, birthdate, url, rate, id}: Hero) { - return new Hero(firstName, lastName, birthdate, url, rate, id); - } constructor( - public firstName: string, - public lastName?: string, + public id?: number, + public name?: string, + public emotion?: string, public birthdate?: Date, public url?: string, public rate = 100, - id?: number) { - - this.id = id != null ? id : Hero.nextId++; + ) { + this.id = id ? id : Hero.nextId++; } - get fullName() { return `${this.firstName} ${this.lastName}`; } + clone(): Hero { + return Object.assign(new Hero(), this); + } } diff --git a/public/docs/_examples/template-syntax/ts/src/index.html b/public/docs/_examples/template-syntax/ts/src/index.html index 418daa58c0..3e711397cb 100644 --- a/public/docs/_examples/template-syntax/ts/src/index.html +++ b/public/docs/_examples/template-syntax/ts/src/index.html @@ -6,7 +6,6 @@ - diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.spec.ts b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.spec.ts index 297e5d7ef8..4e1ee034d7 100644 --- a/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.spec.ts +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.spec.ts @@ -191,7 +191,7 @@ function heroModuleSetup() { })); // #docregion title-case-pipe - it('should convert hero name to Title Case', fakeAsync(() => { + it('should convert hero name to Title Case', () => { const inputName = 'quick BROWN fox'; const titleCaseName = 'Quick Brown Fox'; @@ -205,7 +205,7 @@ function heroModuleSetup() { fixture.detectChanges(); expect(page.nameDisplay.textContent).toBe(titleCaseName); - })); + }); // #enddocregion title-case-pipe // #enddocregion selected-tests // #docregion route-good-id diff --git a/public/docs/ts/latest/glossary.jade b/public/docs/ts/latest/glossary.jade index 4d78201c45..9491f2e35d 100644 --- a/public/docs/ts/latest/glossary.jade +++ b/public/docs/ts/latest/glossary.jade @@ -54,8 +54,10 @@ a#aot :marked In practice, a synonym for [Decoration](#decorator). +a#attribute-directive +a#attribute-directives :marked - ## Attribute directive + ## Attribute directives .l-sub-section :marked A category of [directive](#directive) that can listen to and modify the behavior of @@ -64,6 +66,8 @@ a#aot A good example of an attribute directive is the `ngClass` directive for adding and removing CSS class names. + Learn about them in the [_Attribute Directives_](!{docsLatest}/guide/attribute-directives.html) guide. + .l-main-section#B +ifDocsFor('ts|js') @@ -141,6 +145,7 @@ a#aot This form is also known as **lower camel case**, to distinguish it from **upper camel case**, which is [PascalCase](#pascalcase). When you see "camelCase" in this documentation it always means *lower camel case*. +a#component :marked ## Component .l-sub-section @@ -245,7 +250,7 @@ a#aot that "B" is a dependency of "A". You can ask a "dependency injection system" to create "A" - for us and handle all the dependencies. + and it will handle all of "A"s dependencies. If "A" needs "B" and "B" needs "C", the system resolves that chain of dependencies and returns a fully prepared instance of "A". @@ -276,9 +281,12 @@ a#aot Registering providers is a critical preparatory step. Angular registers some of its own providers with every injector. - We can register our own providers. + You can register your own providers. Read more in the [Dependency Injection](!{docsLatest}/guide/dependency-injection.html) page. + +a#directive +a#directives :marked ## Directive .l-sub-section @@ -286,8 +294,7 @@ a#aot An Angular class responsible for creating, reshaping, 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. + A directive is almost always associated with an HTML element or attribute. When Angular finds a directive in an HTML template, it creates the matching directive class instance and gives the instance control over that portion of the browser DOM. @@ -297,20 +304,19 @@ a#aot as if you were writing native HTML. In this way, directives become extensions of HTML itself. - Directives fall into one of three categories: + Directives fall into three categories: 1. [Components](#component) that combine application logic with an HTML template to - render application [views]. Components are usually represented as HTML elements. + render application [views](#view). 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 + HTML elements, components, and other directives. They are usually represented as HTML attributes, hence the name. - 1. [Structural directives](#structural-directive), a directive responsible for - shaping or reshaping HTML layout, typically by adding, removing, or manipulating - elements and their children. + 1. [Structural directives](#structural-directive) that + shape or reshape HTML layout, typically by adding and removing elements in the DOM. .l-main-section#E @@ -630,21 +636,23 @@ a#snake-case Applications often require services such as a hero data service or a logging service. A service is a class with a focused purpose. - We often create a service to implement features that are + You often create a service to implement features that are independent from any specific view, provide shared data or logic across components, or encapsulate external interactions. For more information, see the [Services](!{docsLatest}/tutorial/toh-pt4.html) page of the [Tour of Heroes](!{docsLatest}/tutorial/) tutorial. +a#structural-directive +a#structural-directives :marked - ## Structural directive + ## Structural directives .l-sub-section :marked A category of [directive](#directive) that can - shape or reshape HTML layout, typically by adding, removing, or manipulating - elements and their children; for example, the `ngIf` "conditional element" directive and the `ngFor` "repeater" directive. + shape or reshape HTML layout, typically by adding and removing elements in the DOM. + The `ngIf` "conditional element" directive and the `ngFor` "repeater" directive are well-known examples. - Read more in the [Structural Directives](!{docsLatest}/guide/structural-directives.html) page. + Read more in the [_Structural Directives_](!{docsLatest}/guide/structural-directives.html) guide. .l-main-section#T :marked @@ -699,8 +707,8 @@ a#snake-case A version of JavaScript that supports most [ECMAScript 2015](#es2015) language features such as [decorators](#decorator). - TypeScript is also noteable for its optional typing system, which gives - us compile-time type checking and strong tooling support (for example, "intellisense", + TypeScript is also noteable for its optional typing system, which enables + compile-time type checking and strong tooling support (for example, "intellisense", code completion, refactoring, and intelligent search). Many code editors and IDEs support TypeScript either natively or with plugins. diff --git a/public/docs/ts/latest/guide/attribute-directives.jade b/public/docs/ts/latest/guide/attribute-directives.jade index 294eab77bb..07bb2f8f5a 100644 --- a/public/docs/ts/latest/guide/attribute-directives.jade +++ b/public/docs/ts/latest/guide/attribute-directives.jade @@ -24,17 +24,20 @@ a#directive-overview ## Directives overview There are three kinds of directives in Angular: - 1. Components—directives with a template. - 1. Structural directives—change the DOM layout by adding and removing DOM elements. - 1. Attribute directives—change the appearance or behavior of an element. + + 1. Components — directives with a template. + 1. Structural directives — change the DOM layout by adding and removing DOM elements. + 1. Attribute directives — change the appearance or behavior of an element, component, or another directive. *Components* are the most common of the three directives. You saw a component for the first time in the [QuickStart](../quickstart.html) example. - *Structural Directives* change the structure of the view. Two examples are [NgFor](template-syntax.html#ngFor) and [NgIf](template-syntax.html#ngIf) - in the [Template Syntax](template-syntax.html) page. + *Structural Directives* change the structure of the view. + Two examples are [NgFor](template-syntax.html#ngFor) and [NgIf](template-syntax.html#ngIf). + Learn about them in the [Structural Directives](structural-directives.html) guide. - *Attribute directives* are used as attributes of elements. The built-in [NgStyle](template-syntax.html#ngStyle) directive in the [Template Syntax](template-syntax.html) page, for example, + *Attribute directives* are used as attributes of elements. + The built-in [NgStyle](template-syntax.html#ngStyle) directive in the [Template Syntax](template-syntax.html) guide, for example, can change several element styles at the same time. .l-main-section diff --git a/public/docs/ts/latest/guide/change-log.jade b/public/docs/ts/latest/guide/change-log.jade index 12ca1a1a12..4eb8cefa75 100644 --- a/public/docs/ts/latest/guide/change-log.jade +++ b/public/docs/ts/latest/guide/change-log.jade @@ -5,6 +5,12 @@ block includes The Angular documentation is a living document with continuous improvements. This log calls attention to recent significant changes. + ## Template Syntax/Structural Directives: refreshed (2017-02-06) + The [_Template-Syntax_](template-syntax.html) and [_Structural Directives_](structural-directives.html) + guides were significantly revised for clarity, accuracy, and current recommended practices. + Discusses ``. + Revised samples are more clear and cover all topics discussed. + ## NEW: Samples re-structured with `src/` folder (2017-02-02) All documentation samples have been realigned with the default folder structure of the angular-cli. That's a step along the road to basing our sample in the angular-cli. @@ -39,7 +45,7 @@ block includes ## Hierarchical Dependency Injection: refreshed (2017-01-13) [Hierarchical Dependency Injection](hierarchical-dependency-injection.html) guide significantly revised. Closes issue #3086 - Revised samples are more clear and cover all topics discussed + Revised samples are more clear and cover all topics discussed. ## Miscellaneous (2017-01-05) * [Setup](setup.html) guide: diff --git a/public/docs/ts/latest/guide/ngcontainer.jade b/public/docs/ts/latest/guide/ngcontainer.jade new file mode 100644 index 0000000000..549bdf7b98 --- /dev/null +++ b/public/docs/ts/latest/guide/ngcontainer.jade @@ -0,0 +1,218 @@ +block includes + include ../_util-fns + +// The docs standard h4 style uppercases, making code terms unreadable. Override it. +style. + h4 {font-size: 17px !important; text-transform: none !important;} + .syntax { font-family: Consolas, 'Lucida Sans', Courier, sans-serif; color: black; font-size: 85%; } + +:marked + This guide has been withdrawn. + The essential information about this feature + is in the [Structural Directives](structural-directives.html#ngcontainer) guide. + The original draft has been retained for possible future use. +// + :marked + The `` tags are part of Angular template syntax. + They help you group HTML template content under a phantom _root_ element + that you can manipulate with [structural directives](#structural-directives.html). + + This guide explains how `` solves certain layout problems. + + ### Table of contents + + - [Introduction](#introduction) + - [The problem](#problem) + - [Troublesome CSS](#CSS) + - [Restrictive layout](#restrictive-layout) + - [<ng-container> is excluded from DOM](#excluded) + - [<ng-container> is not <ng-content>](#ng-content) + - [Summary](#summary) + + Try the . + + a#introduction + .l-main-section + :marked + ## Introduction + + Structural directives are responsible for HTML layout. + They shape or reshape the DOM's _structure_, typically by adding and removing + other elements and their children. + + Two of the common, built-in structural directives are + [NgIf](template-syntax.html#ngIf) and [NgFor](template-syntax.html#ngFor). + You apply these directives to elements that Angular should add and remove. + Usually there's _one_ obvious element to receive the directive. + + Sometimes you need to add or remove a _group of sibling elements_. + You want to apply the directive to the group, not just one of them. + + As this guide explains, you can wrap the elements in an `` and apply the directive to the ``. + + The `` is Angular template syntax for grouping elements, + like the curly braces that group statements in a JavaScript `if` block: + + code-example(language="javascript"). + if (someCondition) { + statement1; + statement2; + statement3; + } + :marked + Without those braces JavaScript could only execute the first statement1 + when you intend to conditionally execute all (or none) of the statements as a single block. + The `` satisfies a similar need in Angular templates. + + The `` _is not_ a directive. + It's not a class or interface or anything you could find in the [API guide](../api "API guide"). + It's just grouping syntax recognized by the Angular parser. + + *Why bother?* Why not wrap the group in standard HTML container element + such as `` or `
`? + + The rest of this guide answers these questions after stepping back and reframing the problem in a bit more detail. + + a#problem + .l-main-section + :marked + ## The problem + + There's often a _root_ element that can and should host the structural directive. + In the following example, the table row (``) should appear only when showing structural directives (when `strucDirs` is `true`). + + +makeExample('ngcontainer/ts/src/app/app.component.html', 'ngif-tr')(format=".") + + :marked + When there isn't a host element, you can usually wrap the content in a native HTML container element, such as a `
`, + and attach the directive to that wrapper. + + +makeExample('ngcontainer/ts/src/app/app.component.html', 'ngif')(format=".") + + :marked + Introducing another container element is usually harmless. + _Usually_ ... but not _always_. + + a#css + :marked + ### Troublesome CSS + + CSS styles can be persnickety about HTML structure, making it difficult to introduce intermediate container elements. + + Suppose you want to display a paragraph with a single sentence that describes the traits of a hero. + figure.image-display + img(src='/resources/images/devguide/ngcontainer/hero-traits-good.png' alt="hero traits") + :marked + For reasons unknown, you can't do the obvious thing and construct the text in a component property. + You must build the sentence in the template instead. + You try a combination of `` wrappers, `*ngIf`, and `*ngFor` and write this. + +makeExample('ngcontainer/ts/src/app/app.component.html', 'ngif-span-2')(format=".") + + :marked + Unfortunately, there's a style that kicks in when a `

`aragraph contains a ``. + +makeExample('ngcontainer/ts/src/app/app.component.css', 'p-span')(format=".") + + :marked + So the sentence renders the spanned text in tiny, red type like this. + figure.image-display + img(src='/resources/images/devguide/ngcontainer/hero-traits-bad.png' alt="hero traits (oops)") + :marked + You could try to fix the CSS ... if you have permission to do so. + The far easier approach is to use `` instead of `` like this. + + +makeExample('ngcontainer/ts/src/app/app.component.html', 'ngif-ngcontainer-2')(format=".") + + a#excluded + :marked + ### <ng-container> is excluded from the DOM + That works. There are no `` tags to trigger the unwanted style. + + Does Angular add an `` to the DOM? + If it did, you'd trip over a similar problem someday, because the introduction of _any_ + HTML for layout purposes is a potential hazard. + + Fortunately, Angular _replaces_ `` _with comments_, which have no effect on styles or layout. + + Inspect the rendered HTML in the browser tools. + You'll see many comments like this: + + code-example(language="html" escape="html"). + <!--template bindings={ + "ng-reflect-ng-if": "true" + }--> + <!--template bindings={} --> + + :marked + You won't find ``. + That's especially important when applying structural directives + to the children of certain troublesome HTML elements. + + a#restrictive-layout + :marked + ### <ng-container> and restrictive layout + + Some HTML elements are picky about their children. + + For example, all children of a `