diff --git a/public/docs/_examples/forms-deprecated/e2e-spec.ts.disabled b/public/docs/_examples/forms-deprecated/e2e-spec.ts.disabled deleted file mode 100644 index ab5c8321be..0000000000 --- a/public/docs/_examples/forms-deprecated/e2e-spec.ts.disabled +++ /dev/null @@ -1,64 +0,0 @@ -/// -'use strict'; -describeIf(browser.appIsTs || browser.appIsJs, 'Forms (Deprecated) Tests', function () { - - beforeEach(function () { - browser.get(''); - }); - - it('should display correct title', function () { - expect(element.all(by.css('h1')).get(0).getText()).toEqual('Hero Form'); - }); - - - it('should not display message before submit', function () { - let ele = element(by.css('h2')); - expect(ele.isDisplayed()).toBe(false); - }); - - it('should hide form after submit', function () { - let ele = element.all(by.css('h1')).get(0); - expect(ele.isDisplayed()).toBe(true); - let b = element.all(by.css('button[type=submit]')).get(0); - b.click().then(function() { - expect(ele.isDisplayed()).toBe(false); - }); - }); - - it('should display message after submit', function () { - let b = element.all(by.css('button[type=submit]')).get(0); - b.click().then(function() { - expect(element(by.css('h2')).getText()).toContain('You submitted the following'); - }); - }); - - it('should hide form after submit', function () { - let alterEgoEle = element.all(by.css('input[ngcontrol=alterEgo]')).get(0); - expect(alterEgoEle.isDisplayed()).toBe(true); - let submitButtonEle = element.all(by.css('button[type=submit]')).get(0); - submitButtonEle.click().then(function() { - expect(alterEgoEle.isDisplayed()).toBe(false); - }); - }); - - it('should reflect submitted data after submit', function () { - let test = 'testing 1 2 3'; - let newValue: string; - let alterEgoEle = element.all(by.css('input[ngcontrol=alterEgo]')).get(0); - alterEgoEle.getAttribute('value').then(function(value) { - // alterEgoEle.sendKeys(test); - sendKeys(alterEgoEle, test); - newValue = value + test; - expect(alterEgoEle.getAttribute('value')).toEqual(newValue); - }).then(function() { - let b = element.all(by.css('button[type=submit]')).get(0); - return b.click(); - }).then(function() { - let alterEgoTextEle = element(by.cssContainingText('div', 'Alter Ego')); - expect(alterEgoTextEle.isPresent()).toBe(true, 'cannot locate "Alter Ego" label'); - let divEle = element(by.cssContainingText('div', newValue)); - expect(divEle.isPresent()).toBe(true, 'cannot locate div with this text: ' + newValue); - }); - }); -}); - diff --git a/public/docs/_examples/forms-deprecated/js/app/app.component.js b/public/docs/_examples/forms-deprecated/js/app/app.component.js deleted file mode 100644 index bb6b789938..0000000000 --- a/public/docs/_examples/forms-deprecated/js/app/app.component.js +++ /dev/null @@ -1,12 +0,0 @@ -// #docregion -(function(app) { - app.AppComponent = ng.core - .Component({ - selector: 'my-app', - template: '', - directives: [app.HeroFormComponent] - }) - .Class({ - constructor: function() {} - }); -})(window.app || (window.app = {})); diff --git a/public/docs/_examples/forms-deprecated/js/app/hero-form.component.html b/public/docs/_examples/forms-deprecated/js/app/hero-form.component.html deleted file mode 100644 index fdf8e08396..0000000000 --- a/public/docs/_examples/forms-deprecated/js/app/hero-form.component.html +++ /dev/null @@ -1,195 +0,0 @@ - - -
- -
-

Hero Form

- -
- - -
- - - -
- Name is required -
- -
- -
- - -
- -
- - -
- Power is required -
-
- - - - -
-
- - -
-

You submitted the following:

-
-
Name
-
{{ model.name }}
-
-
-
Alter Ego
-
{{ model.alterEgo }}
-
-
-
Power
-
{{ model.power }}
-
-
- -
- -
- - - -
-
- - - - -
-
- - - -
- -
- -
-

Hero Form

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

Hero Form

-
- - {{diagnostic()}} -
- - -
- -
- - -
- -
- - -
- - - - -
-
- - - -
- - - TODO: remove this: {{model.name}} - -
- - - TODO: remove this: {{model.name}} - -
-
- - - -
- - -
TODO: remove this: {{spy.className}} - -
- -
-
- Name via form.controls = {{showFormControls(heroForm)}} -
- -
diff --git a/public/docs/_examples/forms-deprecated/js/app/hero-form.component.js b/public/docs/_examples/forms-deprecated/js/app/hero-form.component.js deleted file mode 100644 index 8988231189..0000000000 --- a/public/docs/_examples/forms-deprecated/js/app/hero-form.component.js +++ /dev/null @@ -1,52 +0,0 @@ -// #docplaster -// #docregion -// #docregion first, final -(function(app) { - app.HeroFormComponent = ng.core - .Component({ - selector: 'hero-form', - templateUrl: 'app/hero-form.component.html' - }) - .Class({ - // #docregion submitted - constructor: function() { - // #enddocregion submitted - this.powers = ['Really Smart', 'Super Flexible', - 'Super Hot', 'Weather Changer' - ]; - - this.model = new app.Hero(18, 'Dr IQ', this.powers[0], - 'Chuck Overstreet'); - - // #docregion submitted - this.submitted = false; - }, - onSubmit: function() { - this.submitted = true; - }, - // #enddocregion submitted - - // #enddocregion final - // TODO: Remove this when we're done - diagnostic: function() { - return JSON.stringify(this.model); - }, - // #enddocregion first - - - //////// DO NOT SHOW IN DOCS //////// - - // Reveal in html: - // AlterEgo via form.controls = {{showFormControls(hf)}} - showFormControls: function(form) { - return form.controls['alterEgo'] && - // #docregion form-controls - form.controls['name'].value; // Dr. IQ - // #enddocregion form-controls - }, - ///////////////////////////// - - // #docregion first, final - }); - // #enddocregion first, final -})(window.app || (window.app = {})); diff --git a/public/docs/_examples/forms-deprecated/js/app/hero.js b/public/docs/_examples/forms-deprecated/js/app/hero.js deleted file mode 100644 index 9c2449c922..0000000000 --- a/public/docs/_examples/forms-deprecated/js/app/hero.js +++ /dev/null @@ -1,11 +0,0 @@ -// #docregion -(function(app) { - app.Hero = Hero; - - function Hero(id, name, power, alterEgo) { - this.id = id; - this.name = name; - this.power = power; - this.alterEgo = alterEgo; - } -})(window.app || (window.app = {})); diff --git a/public/docs/_examples/forms-deprecated/js/app/main.js b/public/docs/_examples/forms-deprecated/js/app/main.js deleted file mode 100644 index 5930bdd061..0000000000 --- a/public/docs/_examples/forms-deprecated/js/app/main.js +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -(function(app) { - document.addEventListener('DOMContentLoaded', function() { - ng.platformBrowserDynamic.bootstrap(app.AppComponent); - }); -})(window.app || (window.app = {})); diff --git a/public/docs/_examples/forms-deprecated/js/example-config.json b/public/docs/_examples/forms-deprecated/js/example-config.json deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/public/docs/_examples/forms-deprecated/js/forms.css b/public/docs/_examples/forms-deprecated/js/forms.css deleted file mode 100644 index d7e11405b1..0000000000 --- a/public/docs/_examples/forms-deprecated/js/forms.css +++ /dev/null @@ -1,9 +0,0 @@ -/* #docregion */ -.ng-valid[required] { - border-left: 5px solid #42A948; /* green */ -} - -.ng-invalid { - border-left: 5px solid #a94442; /* red */ -} -/* #enddocregion */ \ No newline at end of file diff --git a/public/docs/_examples/forms-deprecated/js/index.html b/public/docs/_examples/forms-deprecated/js/index.html deleted file mode 100644 index 053f5266fa..0000000000 --- a/public/docs/_examples/forms-deprecated/js/index.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - Hero Form - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Loading... - - - diff --git a/public/docs/_examples/forms-deprecated/js/plnkr.json b/public/docs/_examples/forms-deprecated/js/plnkr.json deleted file mode 100644 index 0105283bd3..0000000000 --- a/public/docs/_examples/forms-deprecated/js/plnkr.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "description": "Forms", - "files":["app/**/*.js", "**/*.html", "**/*.css"] -} diff --git a/public/docs/_examples/forms-deprecated/ts/app/app.component.ts b/public/docs/_examples/forms-deprecated/ts/app/app.component.ts deleted file mode 100644 index 2dcbc8037a..0000000000 --- a/public/docs/_examples/forms-deprecated/ts/app/app.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -import { Component } from '@angular/core'; -import { HeroFormComponent } from './hero-form.component'; - -@Component({ - selector: 'my-app', - template: '', - directives: [HeroFormComponent] -}) -export class AppComponent { } diff --git a/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.html b/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.html deleted file mode 100644 index 6fcfc2a7cb..0000000000 --- a/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.html +++ /dev/null @@ -1,208 +0,0 @@ - - -
- -
-

Hero Form

- -
- - -
- - - - -
- - Name is required -
- -
- -
- - -
- -
- - -
- Power is required -
-
- - - - - - - - - - - -
-
- Name via form.controls = {{showFormControls(heroForm)}} -
- - -
-
- - -
-

You submitted the following:

-
-
Name
-
{{ model.name }}
-
-
-
Alter Ego
-
{{ model.alterEgo }}
-
-
-
Power
-
{{ model.power }}
-
-
- -
- -
- - - -
-
- - - - -
-
- - - -
- -
- -
-

Hero Form

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

Hero Form

-
- - {{diagnostic}} -
- - -
- -
- - -
- -
- - -
- - - - -
-
- - - -
- - - TODO: remove this: {{model.name}} - -
- - - TODO: remove this: {{model.name}} - -
- -
- - - - - -
- - -
TODO: remove this: {{spy.className}} - -
- -
diff --git a/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.ts b/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.ts deleted file mode 100644 index 7ea7c44738..0000000000 --- a/public/docs/_examples/forms-deprecated/ts/app/hero-form.component.ts +++ /dev/null @@ -1,66 +0,0 @@ -// #docplaster -// #docregion -// #docregion first, final -import { Component } from '@angular/core'; -import { NgForm } from '@angular/common'; - -import { Hero } from './hero'; - -@Component({ - selector: 'hero-form', - templateUrl: 'app/hero-form.component.html' -}) -export class HeroFormComponent { - - powers = ['Really Smart', 'Super Flexible', - 'Super Hot', 'Weather Changer']; - - model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet'); - - // #docregion submitted - submitted = false; - - onSubmit() { this.submitted = true; } - // #enddocregion submitted - - // #enddocregion final - // TODO: Remove this when we're done - get diagnostic() { return JSON.stringify(this.model); } - // #enddocregion first - - // #docregion final - // Reset the form with a new hero AND restore 'pristine' class state - // by toggling 'active' flag which causes the form - // to be removed/re-added in a tick via NgIf - // TODO: Workaround until NgForm has a reset method (#6822) - // #docregion new-hero - active = true; - - // #docregion new-hero-v1 - newHero() { - this.model = new Hero(42, '', ''); - // #enddocregion new-hero-v1 - this.active = false; - setTimeout(() => this.active = true, 0); - // #docregion new-hero-v1 - } - // #enddocregion new-hero-v1 - // #enddocregion new-hero - // #enddocregion final - //////// NOT SHOWN IN DOCS //////// - - // Reveal in html: - // Name via form.controls = {{showFormControls(heroForm)}} - showFormControls(form: NgForm) { - - return form && form.controls['name'] && - // #docregion form-controls - form.controls['name'].value; // Dr. IQ - // #enddocregion form-controls - } - - ///////////////////////////// - - // #docregion first, final -} -// #enddocregion first, final diff --git a/public/docs/_examples/forms-deprecated/ts/app/hero.ts b/public/docs/_examples/forms-deprecated/ts/app/hero.ts deleted file mode 100644 index c128626452..0000000000 --- a/public/docs/_examples/forms-deprecated/ts/app/hero.ts +++ /dev/null @@ -1,11 +0,0 @@ -// #docregion -export class Hero { - - constructor( - public id: number, - public name: string, - public power: string, - public alterEgo?: string - ) { } - -} diff --git a/public/docs/_examples/forms-deprecated/ts/app/main.ts b/public/docs/_examples/forms-deprecated/ts/app/main.ts deleted file mode 100644 index 5338161d66..0000000000 --- a/public/docs/_examples/forms-deprecated/ts/app/main.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -import { bootstrap } from '@angular/platform-browser-dynamic'; - -import { AppComponent } from './app.component'; - -bootstrap(AppComponent); diff --git a/public/docs/_examples/forms-deprecated/ts/example-config.json b/public/docs/_examples/forms-deprecated/ts/example-config.json deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/public/docs/_examples/forms-deprecated/ts/forms.css b/public/docs/_examples/forms-deprecated/ts/forms.css deleted file mode 100644 index d7e11405b1..0000000000 --- a/public/docs/_examples/forms-deprecated/ts/forms.css +++ /dev/null @@ -1,9 +0,0 @@ -/* #docregion */ -.ng-valid[required] { - border-left: 5px solid #42A948; /* green */ -} - -.ng-invalid { - border-left: 5px solid #a94442; /* red */ -} -/* #enddocregion */ \ No newline at end of file diff --git a/public/docs/_examples/forms-deprecated/ts/index.html b/public/docs/_examples/forms-deprecated/ts/index.html deleted file mode 100644 index 4df2d32d46..0000000000 --- a/public/docs/_examples/forms-deprecated/ts/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - Hero Form - - - - - - - - - - - - - - - - - - - - - - - - Loading... - - - diff --git a/public/docs/_examples/forms-deprecated/ts/plnkr.json b/public/docs/_examples/forms-deprecated/ts/plnkr.json deleted file mode 100644 index c813933f8e..0000000000 --- a/public/docs/_examples/forms-deprecated/ts/plnkr.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "description": "Forms-Deprecated", - "files":[ - "!**/*.d.ts", - "!**/*.js" - ] -} \ No newline at end of file diff --git a/public/docs/_examples/router-deprecated/e2e-spec.ts.disabled b/public/docs/_examples/router-deprecated/e2e-spec.ts.disabled deleted file mode 100644 index 3892285845..0000000000 --- a/public/docs/_examples/router-deprecated/e2e-spec.ts.disabled +++ /dev/null @@ -1,127 +0,0 @@ -/// -'use strict'; -describe('Router', function () { - - beforeAll(function () { - browser.get(''); - }); - - function getPageStruct() { - let hrefEles = element.all(by.css('my-app a')); - - return { - hrefs: hrefEles, - routerParent: element(by.css('my-app > undefined')), - routerTitle: element(by.css('my-app > undefined > h2')), - - crisisHref: hrefEles.get(0), - crisisList: element.all(by.css('my-app > undefined > undefined li')), - crisisDetail: element(by.css('my-app > undefined > undefined > div')), - crisisDetailTitle: element(by.css('my-app > undefined > undefined > div > h3')), - - heroesHref: hrefEles.get(1), - heroesList: element.all(by.css('my-app > undefined li')), - heroDetail: element(by.css('my-app > undefined > div')), - heroDetailTitle: element(by.css('my-app > undefined > div > h3')), - - }; - } - - it('should be able to see the start screen', function () { - let page = getPageStruct(); - expect(page.hrefs.count()).toEqual(2, 'should be two dashboard choices'); - expect(page.crisisHref.getText()).toEqual('Crisis Center'); - expect(page.heroesHref.getText()).toEqual('Heroes'); - }); - - it('should be able to see crises center items', function () { - let page = getPageStruct(); - expect(page.crisisList.count()).toBe(4, 'should be 4 crisis center entries at start'); - }); - - it('should be able to see hero items', function () { - let page = getPageStruct(); - page.heroesHref.click().then(function() { - expect(page.routerTitle.getText()).toContain('HEROES'); - expect(page.heroesList.count()).toBe(6, 'should be 6 heroes'); - }); - }); - - it('should be able to toggle the views', function () { - let page = getPageStruct(); - page.crisisHref.click().then(function() { - expect(page.crisisList.count()).toBe(4, 'should be 4 crisis center entries'); - return page.heroesHref.click(); - }).then(function() { - expect(page.heroesList.count()).toBe(6, 'should be 6 heroes'); - }); - }); - - it('should be able to edit and save details from the crisis center view', function () { - crisisCenterEdit(2, true); - }); - - it('should be able to edit and cancel details from the crisis center view', function () { - crisisCenterEdit(3, false); - }); - - it('should be able to edit and save details from the heroes view', function () { - let page = getPageStruct(); - let heroEle: protractor.ElementFinder; - let heroText: string; - page.heroesHref.click().then(function() { - heroEle = page.heroesList.get(4); - return heroEle.getText(); - }).then(function(text) { - expect(text.length).toBeGreaterThan(0, 'should have some text'); - // remove leading id from text - heroText = text.substr(text.indexOf(' ')).trim(); - return heroEle.click(); - }).then(function() { - expect(page.heroesList.count()).toBe(0, 'should no longer see crisis center entries'); - expect(page.heroDetail.isPresent()).toBe(true, 'should be able to see crisis detail'); - expect(page.heroDetailTitle.getText()).toContain(heroText); - let inputEle = page.heroDetail.element(by.css('input')); - return sendKeys(inputEle, '-foo'); - }).then(function() { - expect(page.heroDetailTitle.getText()).toContain(heroText + '-foo'); - let buttonEle = page.heroDetail.element(by.css('button')); - return buttonEle.click(); - }).then(function() { - expect(heroEle.getText()).toContain(heroText + '-foo'); - }); - }); - - function crisisCenterEdit(index: number, shouldSave: boolean) { - let page = getPageStruct(); - let crisisEle: protractor.ElementFinder; - let crisisText: string; - page.crisisHref.click() - .then(function () { - crisisEle = page.crisisList.get(index); - return crisisEle.getText(); - }).then(function (text) { - expect(text.length).toBeGreaterThan(0, 'should have some text'); - // remove leading id from text - crisisText = text.substr(text.indexOf(' ')).trim(); - return crisisEle.click(); - }).then(function () { - expect(page.crisisList.count()).toBe(0, 'should no longer see crisis center entries'); - expect(page.crisisDetail.isPresent()).toBe(true, 'should be able to see crisis detail'); - expect(page.crisisDetailTitle.getText()).toContain(crisisText); - let inputEle = page.crisisDetail.element(by.css('input')); - return sendKeys(inputEle, '-foo'); - }).then(function () { - expect(page.crisisDetailTitle.getText()).toContain(crisisText + '-foo'); - let buttonEle = page.crisisDetail.element(by.cssContainingText('button', shouldSave ? 'Save' : 'Cancel')); - return buttonEle.click(); - }).then(function () { - if (shouldSave) { - expect(crisisEle.getText()).toContain(crisisText + '-foo'); - } else { - expect(crisisEle.getText()).not.toContain(crisisText + '-foo'); - } - }); - } - -}); diff --git a/public/docs/_examples/router-deprecated/ts/app/app.component.1.ts b/public/docs/_examples/router-deprecated/ts/app/app.component.1.ts deleted file mode 100644 index 0e20623fd3..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/app.component.1.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* First version */ -// #docplaster - -// #docregion -import { Component } from '@angular/core'; -// #docregion import-router -import { RouteConfig, ROUTER_DIRECTIVES } from '@angular/router-deprecated'; -// #enddocregion import-router - -import { CrisisListComponent } from './crisis-list.component'; -import { HeroListComponent } from './hero-list.component'; - -@Component({ - selector: 'my-app', -// #docregion template - template: ` -

Component Router (Deprecated)

- - - `, -// #enddocregion template - directives: [ROUTER_DIRECTIVES] -}) -// #enddocregion -/* -// #docregion route-config -@Component({ ... }) -// #enddocregion route-config -*/ -// #docregion -// #docregion route-config -@RouteConfig([ -// #docregion route-defs - {path: '/crisis-center', name: 'CrisisCenter', component: CrisisListComponent}, - {path: '/heroes', name: 'Heroes', component: HeroListComponent} -// #enddocregion route-defs -]) -export class AppComponent { } -// #enddocregion route-config -// #enddocregion diff --git a/public/docs/_examples/router-deprecated/ts/app/app.component.2.ts b/public/docs/_examples/router-deprecated/ts/app/app.component.2.ts deleted file mode 100644 index e4685ff418..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/app.component.2.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* Second Heroes version */ -// #docplaster - -// #docregion -import { Component } from '@angular/core'; -import { RouteConfig, ROUTER_DIRECTIVES } from '@angular/router-deprecated'; - -import { CrisisListComponent } from './crisis-list.component'; -// #enddocregion -/* -// Apparent Milestone 2 imports -// #docregion -// #docregion hero-import -import { HeroListComponent } from './heroes/hero-list.component'; -import { HeroDetailComponent } from './heroes/hero-detail.component'; -import { HeroService } from './heroes/hero.service'; -// #enddocregion hero-import -// #enddocregion -*/ -// Actual Milestone 2 imports -import { HeroListComponent } from './heroes/hero-list.component.1'; -import { HeroDetailComponent } from './heroes/hero-detail.component.1'; -import { HeroService } from './heroes/hero.service'; -// #docregion - -@Component({ - selector: 'my-app', - template: ` -

Component Router (Deprecated)

- - - `, - providers: [HeroService], - directives: [ROUTER_DIRECTIVES] -}) -// #enddocregion -/* -// #docregion route-config -@Component({ ... }) -// #enddocregion route-config -*/ -// #docregion -// #docregion route-config -@RouteConfig([ -// #docregion route-defs - {path: '/crisis-center', name: 'CrisisCenter', component: CrisisListComponent}, - {path: '/heroes', name: 'Heroes', component: HeroListComponent}, - // #docregion hero-detail-route - {path: '/hero/:id', name: 'HeroDetail', component: HeroDetailComponent} - // #enddocregion hero-detail-route -// #enddocregion route-defs -]) -export class AppComponent { } -// #enddocregion route-config -// #enddocregion diff --git a/public/docs/_examples/router-deprecated/ts/app/app.component.3.ts b/public/docs/_examples/router-deprecated/ts/app/app.component.3.ts deleted file mode 100644 index 68635e8aad..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/app.component.3.ts +++ /dev/null @@ -1,52 +0,0 @@ -// #docplaster -import { Component } from '@angular/core'; -import { RouteConfig, ROUTER_DIRECTIVES } from '@angular/router-deprecated'; - -import { CrisisCenterComponent } from './crisis-center/crisis-center.component.1'; -import { DialogService } from './dialog.service'; -import { HeroService } from './heroes/hero.service'; - -@Component({ - selector: 'my-app', -// #enddocregion - /* Typical link - // #docregion h-anchor - Heroes - // #enddocregion h-anchor - */ - /* Incomplete Crisis Center link when CC lacks a default - // #docregion cc-anchor-fail - // The link now fails with a "non-terminal link" error - // #docregion cc-anchor-w-default - Crisis Center - // #enddocregion cc-anchor-w-default - // #enddocregion cc-anchor-fail - */ - /* Crisis Center link when CC lacks a default - // #docregion cc-anchor-no-default - Crisis Center - // #enddocregion cc-anchor-no-default - */ - /* Crisis Center Detail link - // #docregion Dragon-anchor - Dragon Crisis - // #enddocregion Dragon-anchor - */ -// #docregion template - template: ` -

Component Router (Deprecated)

- - - `, -// #enddocregion template - providers: [DialogService, HeroService], - directives: [ROUTER_DIRECTIVES] -}) -@RouteConfig([ - {path: '/crisis-center/...', name: 'CrisisCenter', component: CrisisCenterComponent}, -]) -export class AppComponent { } diff --git a/public/docs/_examples/router-deprecated/ts/app/app.component.ts b/public/docs/_examples/router-deprecated/ts/app/app.component.ts deleted file mode 100644 index a6f784cda9..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/app.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -// #docplaster -// #docregion -import { Component } from '@angular/core'; -import { RouteConfig, ROUTER_DIRECTIVES } from '@angular/router-deprecated'; - -import { CrisisCenterComponent } from './crisis-center/crisis-center.component'; -import { HeroListComponent } from './heroes/hero-list.component'; -import { HeroDetailComponent } from './heroes/hero-detail.component'; - -import { DialogService } from './dialog.service'; -import { HeroService } from './heroes/hero.service'; - -@Component({ - selector: 'my-app', -// #docregion template - template: ` -

Component Router (Deprecated)

- - - `, -// #enddocregion template - providers: [DialogService, HeroService], - directives: [ROUTER_DIRECTIVES] -}) -// #docregion route-config -@RouteConfig([ - - // #docregion route-config-cc - { // Crisis Center child route - path: '/crisis-center/...', - name: 'CrisisCenter', - component: CrisisCenterComponent, - useAsDefault: true - }, - // #enddocregion route-config-cc - - {path: '/heroes', name: 'Heroes', component: HeroListComponent}, - {path: '/hero/:id', name: 'HeroDetail', component: HeroDetailComponent}, -]) -// #enddocregion route-config -export class AppComponent { } diff --git a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-center.component.1.ts b/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-center.component.1.ts deleted file mode 100644 index 6925fb8008..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-center.component.1.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Component } from '@angular/core'; -import { RouteConfig, RouterOutlet } from '@angular/router-deprecated'; - -import { CrisisListComponent } from './crisis-list.component.1'; -import { CrisisDetailComponent } from './crisis-detail.component.1'; -import { CrisisService } from './crisis.service'; - -// #docregion minus-imports -@Component({ - template: ` -

CRISIS CENTER

- - `, - directives: [RouterOutlet], -// #docregion providers - providers: [CrisisService] -// #enddocregion providers -}) -// #docregion route-config -@RouteConfig([ - // #docregion default-route - {path: '/', name: 'CrisisList', component: CrisisListComponent, useAsDefault: true}, - // #enddocregion default-route - {path: '/:id', name: 'CrisisDetail', component: CrisisDetailComponent} -]) -// #enddocregion route-config -export class CrisisCenterComponent { } -// #enddocregion minus-imports diff --git a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-center.component.ts b/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-center.component.ts deleted file mode 100644 index 3c735ae6ae..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-center.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion -import { Component } from '@angular/core'; -import { RouteConfig, RouterOutlet } from '@angular/router-deprecated'; - -import { CrisisListComponent } from './crisis-list.component'; -import { CrisisDetailComponent } from './crisis-detail.component'; -import { CrisisService } from './crisis.service'; - -@Component({ - template: ` -

CRISIS CENTER

- - `, - directives: [RouterOutlet], - providers: [CrisisService] -}) -@RouteConfig([ - {path: '/', name: 'CrisisList', component: CrisisListComponent, useAsDefault: true}, - {path: '/:id', name: 'CrisisDetail', component: CrisisDetailComponent} -]) -export class CrisisCenterComponent { } -// #enddocregion diff --git a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-detail.component.1.ts b/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-detail.component.1.ts deleted file mode 100644 index 0c683853c9..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-detail.component.1.ts +++ /dev/null @@ -1,95 +0,0 @@ -// #docplaster - -// #docregion -import { Component, OnInit } from '@angular/core'; -import { RouteParams, Router } from '@angular/router-deprecated'; -// #docregion routerCanDeactivate -import { CanDeactivate, ComponentInstruction } from '@angular/router-deprecated'; - -import { DialogService } from '../dialog.service'; - -// #enddocregion routerCanDeactivate -import { Crisis, CrisisService } from './crisis.service'; - -@Component({ - // #docregion template - template: ` -
-

"{{editName}}"

-
- {{crisis.id}}
-
- - -
-

- - -

-
- `, - // #enddocregion template - styles: ['input {width: 20em}'] -}) -// #docregion routerCanDeactivate, cancel-save -export class CrisisDetailComponent implements OnInit, CanDeactivate { - - crisis: Crisis; - editName: string; - -// #enddocregion routerCanDeactivate, cancel-save - constructor( - private service: CrisisService, - private router: Router, - private routeParams: RouteParams, - private dialog: DialogService - ) { } - - // #docregion ngOnInit - ngOnInit() { - let id = +this.routeParams.get('id'); - this.service.getCrisis(id).then(crisis => { - if (crisis) { - this.editName = crisis.name; - this.crisis = crisis; - } else { // id not found - this.gotoCrises(); - } - }); - } - // #enddocregion ngOnInit - - // #docregion routerCanDeactivate - routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction): any { - // Allow synchronous navigation (`true`) if no crisis or the crisis is unchanged. - if (!this.crisis || this.crisis.name === this.editName) { - return true; - } - // Otherwise ask the user with the dialog service and return its - // promise which resolves to true or false when the user decides - return this.dialog.confirm('Discard changes?'); - } - // #enddocregion routerCanDeactivate - - // #docregion cancel-save - cancel() { - this.editName = this.crisis.name; - this.gotoCrises(); - } - - save() { - this.crisis.name = this.editName; - this.gotoCrises(); - } - // #enddocregion cancel-save - - // #docregion gotoCrises - gotoCrises() { - // Like Crisis Center -

"{{editName}}"

-
- {{crisis.id}}
-
- - -
-

- - -

- - `, - styles: ['input {width: 20em}'] -}) - -export class CrisisDetailComponent implements OnInit, CanDeactivate { - - crisis: Crisis; - editName: string; - - constructor( - private service: CrisisService, - private router: Router, - private routeParams: RouteParams, - private _dialog: DialogService - ) { } - - ngOnInit() { - let id = +this.routeParams.get('id'); - this.service.getCrisis(id).then(crisis => { - if (crisis) { - this.editName = crisis.name; - this.crisis = crisis; - } else { // id not found - this.gotoCrises(); - } - }); - } - - routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction): any { - // Allow synchronous navigation (`true`) if no crisis or the crisis is unchanged. - if (!this.crisis || this.crisis.name === this.editName) { - return true; - } - // Otherwise ask the user with the dialog service and return its - // promise which resolves to true or false when the user decides - return this._dialog.confirm('Discard changes?'); - } - - cancel() { - this.editName = this.crisis.name; - this.gotoCrises(); - } - - save() { - this.crisis.name = this.editName; - this.gotoCrises(); - } - - // #docregion gotoCrises - gotoCrises() { - let crisisId = this.crisis ? this.crisis.id : null; - // Pass along the hero id if available - // so that the CrisisListComponent can select that hero. - // Add a totally useless `foo` parameter for kicks. - // #docregion gotoCrises-navigate - this.router.navigate(['CrisisList', {id: crisisId, foo: 'foo'} ]); - // #enddocregion gotoCrises-navigate - } - // #enddocregion gotoCrises -} diff --git a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-list.component.1.ts b/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-list.component.1.ts deleted file mode 100644 index 45121da69e..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-list.component.1.ts +++ /dev/null @@ -1,37 +0,0 @@ -// #docplaster - -// #docregion -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router-deprecated'; - -import { Crisis, CrisisService } from './crisis.service'; - -@Component({ - // #docregion template - template: ` - - `, - // #enddocregion template -}) -export class CrisisListComponent implements OnInit { - crises: Crisis[]; - - constructor( - private service: CrisisService, - private router: Router) {} - - ngOnInit() { - this.service.getCrises().then(crises => this.crises = crises); - } - - // #docregion select - onSelect(crisis: Crisis) { - this.router.navigate(['CrisisDetail', { id: crisis.id }] ); - } - // #enddocregion select -} diff --git a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-list.component.ts b/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-list.component.ts deleted file mode 100644 index a5770d256f..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis-list.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -// #docplaster - -// #docregion -import { Component, OnInit } from '@angular/core'; -import { RouteParams, Router } from '@angular/router-deprecated'; - -import { Crisis, CrisisService } from './crisis.service'; - -@Component({ - template: ` - - `, -}) -export class CrisisListComponent implements OnInit { - crises: Crisis[]; - - private selectedId: number; - - constructor( - private service: CrisisService, - private router: Router, - routeParams: RouteParams) { - this.selectedId = +routeParams.get('id'); - } - - isSelected(crisis: Crisis) { return crisis.id === this.selectedId; } - - ngOnInit() { - this.service.getCrises().then(crises => this.crises = crises); - } - - onSelect(crisis: Crisis) { - this.router.navigate( ['CrisisDetail', { id: crisis.id }] ); - } -} diff --git a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis.service.ts b/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis.service.ts deleted file mode 100644 index a847a15217..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/crisis-center/crisis.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -// #docplaster -// #docregion -import { Injectable } from '@angular/core'; - -export class Crisis { - constructor(public id: number, public name: string) { } -} - -let crises = [ - new Crisis(1, 'Dragon Burning Cities'), - new Crisis(2, 'Sky Rains Great White Sharks'), - new Crisis(3, 'Giant Asteroid Heading For Earth'), - new Crisis(4, 'Procrastinators Meeting Delayed Again'), -]; - -let crisesPromise = Promise.resolve(crises); - -@Injectable() -export class CrisisService { - getCrises() { return crisesPromise; } - - getCrisis(id: number | string) { - return crisesPromise - .then(crises => crises.find(c => c.id === +id)); - } - -// #enddocregion - - static nextCrisisId = 100; - - addCrisis(name: string) { - name = name.trim(); - if (name) { - let crisis = new Crisis(CrisisService.nextCrisisId++, name); - crisesPromise.then(crises => crises.push(crisis)); - } - } -// #docregion -} -// #enddocregion diff --git a/public/docs/_examples/router-deprecated/ts/app/crisis-list.component.ts b/public/docs/_examples/router-deprecated/ts/app/crisis-list.component.ts deleted file mode 100644 index 6caa3653b5..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/crisis-list.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Initial empty version -// #docregion -import { Component } from '@angular/core'; - -@Component({ - template: ` -

CRISIS CENTER

-

Get your crisis here

` -}) -export class CrisisListComponent { } diff --git a/public/docs/_examples/router-deprecated/ts/app/dialog.service.ts b/public/docs/_examples/router-deprecated/ts/app/dialog.service.ts deleted file mode 100644 index 71a342cbe8..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/dialog.service.ts +++ /dev/null @@ -1,18 +0,0 @@ -// #docregion -import { Injectable } from '@angular/core'; -/** - * Async modal dialog service - * DialogService makes this app easier to test by faking this service. - * TODO: better modal implementation that doesn't use window.confirm - */ -@Injectable() -export class DialogService { - /** - * Ask user to confirm an action. `message` explains the action and choices. - * Returns promise resolving to `true`=confirm or `false`=cancel - */ - confirm(message?: string) { - return new Promise((resolve, reject) => - resolve(window.confirm(message || 'Is it OK?'))); - }; -} diff --git a/public/docs/_examples/router-deprecated/ts/app/hero-list.component.ts b/public/docs/_examples/router-deprecated/ts/app/hero-list.component.ts deleted file mode 100644 index 5dbbe17d8e..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/hero-list.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// Initial empty version -// #docregion -import { Component } from '@angular/core'; - -@Component({ - template: ` -

HEROES

-

Get your heroes here

` -}) -export class HeroListComponent { } diff --git a/public/docs/_examples/router-deprecated/ts/app/heroes/hero-detail.component.1.ts b/public/docs/_examples/router-deprecated/ts/app/heroes/hero-detail.component.1.ts deleted file mode 100644 index ebfa0bf21d..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/heroes/hero-detail.component.1.ts +++ /dev/null @@ -1,47 +0,0 @@ -// #docregion -import { Component, OnInit } from '@angular/core'; -import { RouteParams, Router } from '@angular/router-deprecated'; - -import { Hero, HeroService } from './hero.service'; - -@Component({ - template: ` -

HEROES

-
-

"{{hero.name}}"

-
- {{hero.id}}
-
- - -
-

- -

-
- `, -}) -export class HeroDetailComponent implements OnInit { - hero: Hero; - - // #docregion ctor - constructor( - private router: Router, - private routeParams: RouteParams, - private service: HeroService) {} - // #enddocregion ctor - - // #docregion ngOnInit - ngOnInit() { - let id = this.routeParams.get('id'); - this.service.getHero(id).then(hero => this.hero = hero); - } - // #enddocregion ngOnInit - - // #docregion gotoHeroes - gotoHeroes() { - // Like Heroes - this.router.navigate(['Heroes']); - } - // #enddocregion gotoHeroes -} diff --git a/public/docs/_examples/router-deprecated/ts/app/heroes/hero-detail.component.ts b/public/docs/_examples/router-deprecated/ts/app/heroes/hero-detail.component.ts deleted file mode 100644 index 10e73fd27b..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/heroes/hero-detail.component.ts +++ /dev/null @@ -1,52 +0,0 @@ -// #docregion -import { Component, OnInit } from '@angular/core'; -import { RouteParams, Router } from '@angular/router-deprecated'; - -import { Hero, HeroService } from './hero.service'; - -@Component({ - template: ` -

HEROES

-
-

"{{hero.name}}"

-
- {{hero.id}}
-
- - -
-

- -

-
- `, -}) -export class HeroDetailComponent implements OnInit { - hero: Hero; - - // #docregion ctor - constructor( - private router: Router, - private routeParams: RouteParams, - private service: HeroService) {} - // #enddocregion ctor - - // #docregion ngOnInit - ngOnInit() { - let id = this.routeParams.get('id'); - this.service.getHero(id).then(hero => this.hero = hero); - } - // #enddocregion ngOnInit - - // #docregion gotoHeroes - gotoHeroes() { - let heroId = this.hero ? this.hero.id : null; - // Pass along the hero id if available - // so that the HeroList component can select that hero. - // Add a totally useless `foo` parameter for kicks. - // #docregion gotoHeroes-navigate - this.router.navigate(['Heroes', {id: heroId, foo: 'foo'} ]); - // #enddocregion gotoHeroes-navigate - } - // #enddocregion gotoHeroes -} diff --git a/public/docs/_examples/router-deprecated/ts/app/heroes/hero-list.component.1.ts b/public/docs/_examples/router-deprecated/ts/app/heroes/hero-list.component.1.ts deleted file mode 100644 index cb1d20327c..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/heroes/hero-list.component.1.ts +++ /dev/null @@ -1,50 +0,0 @@ -// #docplaster - -// #docregion -// TODO SOMEDAY: Feature Componetized like HeroCenter -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router-deprecated'; - -import { Hero, HeroService } from './hero.service'; - -@Component({ - // #docregion template - template: ` -

HEROES

-
    -
  • - {{hero.id}} {{hero.name}} -
  • -
- ` - // #enddocregion template -}) -export class HeroListComponent implements OnInit { - heroes: Hero[]; - - // #docregion ctor - constructor( - private router: Router, - private service: HeroService) { } - // #enddocregion ctor - - ngOnInit() { - this.service.getHeroes().then(heroes => this.heroes = heroes); - } - - // #docregion select - onSelect(hero: Hero) { - // #docregion nav-to-detail - this.router.navigate( ['HeroDetail', { id: hero.id }] ); - // #enddocregion nav-to-detail - } - // #enddocregion select -} -// #enddocregion - -/* A link parameters array -// #docregion link-parameters-array -['HeroDetail', { id: hero.id }] // {id: 15} -// #enddocregion link-parameters-array -*/ diff --git a/public/docs/_examples/router-deprecated/ts/app/heroes/hero-list.component.ts b/public/docs/_examples/router-deprecated/ts/app/heroes/hero-list.component.ts deleted file mode 100644 index 1ca787592f..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/heroes/hero-list.component.ts +++ /dev/null @@ -1,56 +0,0 @@ -// #docplaster - -// TODO SOMEDAY: Feature Componetized like CrisisCenter -// #docregion -import { Component, OnInit } from '@angular/core'; -// #docregion import-route-params -import { RouteParams, Router } from '@angular/router-deprecated'; -// #enddocregion import-route-params - -import { Hero, HeroService } from './hero.service'; - -@Component({ - // #docregion template - template: ` -

HEROES

-
    -
  • - {{hero.id}} {{hero.name}} -
  • -
- ` - // #enddocregion template -}) -export class HeroListComponent implements OnInit { - heroes: Hero[]; - - // #docregion ctor - private selectedId: number; - - constructor( - private service: HeroService, - private router: Router, - routeParams: RouteParams) { - this.selectedId = +routeParams.get('id'); - } - // #enddocregion ctor - - // #docregion isSelected - isSelected(hero: Hero) { return hero.id === this.selectedId; } - // #enddocregion isSelected - - // #docregion select - onSelect(hero: Hero) { - this.router.navigate( ['HeroDetail', { id: hero.id }] ); - } - // #enddocregion select - - ngOnInit() { - - - this.service.getHeroes().then(heroes => this.heroes = heroes); - } -} -// #enddocregion diff --git a/public/docs/_examples/router-deprecated/ts/app/heroes/hero.service.ts b/public/docs/_examples/router-deprecated/ts/app/heroes/hero.service.ts deleted file mode 100644 index c819bd2632..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/heroes/hero.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -// #docregion -import { Injectable } from '@angular/core'; - -export class Hero { - constructor(public id: number, public name: string) { } -} - -let HEROES = [ - new Hero(11, 'Mr. Nice'), - new Hero(12, 'Narco'), - new Hero(13, 'Bombasto'), - new Hero(14, 'Celeritas'), - new Hero(15, 'Magneta'), - new Hero(16, 'RubberMan') -]; - -let heroesPromise = Promise.resolve(HEROES); - -@Injectable() -export class HeroService { - getHeroes() { return heroesPromise; } - - getHero(id: number | string) { - return heroesPromise - .then(heroes => heroes.find(h => h.id === +id)); - } -} diff --git a/public/docs/_examples/router-deprecated/ts/app/main.1.ts b/public/docs/_examples/router-deprecated/ts/app/main.1.ts deleted file mode 100644 index ce110455d4..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/main.1.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* First version */ -// #docplaster - -// #docregion all -import { bootstrap } from '@angular/platform-browser-dynamic'; -import { ROUTER_PROVIDERS } from '@angular/router-deprecated'; - -import { AppComponent } from './app.component'; - -// #enddocregion all - -/* Can't use AppComponent ... but display as if we can -// #docregion all -bootstrap(AppComponent, [ -// #enddocregion all -*/ - -// Actually use the v.1 component -import { AppComponent as ac } from './app.component.1'; -bootstrap(ac, [ -// #docregion all - ROUTER_PROVIDERS -]); -// #enddocregion all diff --git a/public/docs/_examples/router-deprecated/ts/app/main.2.ts b/public/docs/_examples/router-deprecated/ts/app/main.2.ts deleted file mode 100644 index 74862cdd0a..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/main.2.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* Second version */ -// For Milestone #2 -// Also includes digression on HashPathStrategy (not used in the final app) -// #docplaster - -// #docregion -import { bootstrap } from '@angular/platform-browser-dynamic'; -import { ROUTER_PROVIDERS } from '@angular/router-deprecated'; - -// Add these symbols to override the `LocationStrategy` -import { LocationStrategy, - HashLocationStrategy } from '@angular/common'; - -import { AppComponent } from './app.component'; -// #enddocregion -/* Can't use AppComponent ... but display as if we can -// #docregion - -bootstrap(AppComponent, [ -// #enddocregion -*/ - -// Actually use the v.2 component -import { AppComponent as ac } from './app.component.2'; - -bootstrap(ac, [ -// #docregion - ROUTER_PROVIDERS, - { provide: LocationStrategy, useClass: HashLocationStrategy } // .../#/crisis-center/ -]); -// #enddocregion diff --git a/public/docs/_examples/router-deprecated/ts/app/main.3.ts b/public/docs/_examples/router-deprecated/ts/app/main.3.ts deleted file mode 100644 index 9e9eb04721..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/main.3.ts +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import { bootstrap } from '@angular/platform-browser-dynamic'; -import { ROUTER_PROVIDERS } from '@angular/router-deprecated'; - -import { AppComponent } from './app.component.3'; - -bootstrap(AppComponent, [ROUTER_PROVIDERS]); diff --git a/public/docs/_examples/router-deprecated/ts/app/main.ts b/public/docs/_examples/router-deprecated/ts/app/main.ts deleted file mode 100644 index 08bbbef6e8..0000000000 --- a/public/docs/_examples/router-deprecated/ts/app/main.ts +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import { bootstrap } from '@angular/platform-browser-dynamic'; -import { ROUTER_PROVIDERS } from '@angular/router-deprecated'; - -import { AppComponent } from './app.component'; - -bootstrap(AppComponent, [ROUTER_PROVIDERS]); diff --git a/public/docs/_examples/router-deprecated/ts/example-config.json b/public/docs/_examples/router-deprecated/ts/example-config.json deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/public/docs/_examples/router-deprecated/ts/index.1.html b/public/docs/_examples/router-deprecated/ts/index.1.html deleted file mode 100644 index 53a6d4832f..0000000000 --- a/public/docs/_examples/router-deprecated/ts/index.1.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - Router (Deprecated) Sample v.1 - - - - - - - - - - - - - - - - -

Milestone 1

- loading... - - - - diff --git a/public/docs/_examples/router-deprecated/ts/index.2.html b/public/docs/_examples/router-deprecated/ts/index.2.html deleted file mode 100644 index d71bd929cb..0000000000 --- a/public/docs/_examples/router-deprecated/ts/index.2.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - Router (Deprecated) Sample v.2 - - - - - - - - - - - - - - - - -

Milestone 2

- loading... - - - - diff --git a/public/docs/_examples/router-deprecated/ts/index.3.html b/public/docs/_examples/router-deprecated/ts/index.3.html deleted file mode 100644 index abbb771beb..0000000000 --- a/public/docs/_examples/router-deprecated/ts/index.3.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - Router (Deprecated) Sample v.3 - - - - - - - - - - - - - - - - -

Milestone 3

- loading... - - - - diff --git a/public/docs/_examples/router-deprecated/ts/index.html b/public/docs/_examples/router-deprecated/ts/index.html deleted file mode 100644 index 35a6ddfc73..0000000000 --- a/public/docs/_examples/router-deprecated/ts/index.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - Router (Deprecated) Sample - - - - - - - - - - - - - - - - - loading... - - - - diff --git a/public/docs/_examples/router-deprecated/ts/plnkr.json b/public/docs/_examples/router-deprecated/ts/plnkr.json deleted file mode 100644 index 91eff6fdb9..0000000000 --- a/public/docs/_examples/router-deprecated/ts/plnkr.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "description": "Router (Deprecated Beta)", - "files":[ - "!**/*.d.ts", - "!**/*.js", - "!**/*.[1,2,3].*", - "!app/crisis-list.component.ts", - "!app/hero-list.component.ts", - "!app/crisis-center/add-crisis.component.ts" - ], - "tags": ["router", "deprecated"] -} diff --git a/public/docs/dart/latest/guide/_data.json b/public/docs/dart/latest/guide/_data.json index 8b9f230bd6..f13c3c42c8 100644 --- a/public/docs/dart/latest/guide/_data.json +++ b/public/docs/dart/latest/guide/_data.json @@ -36,13 +36,6 @@ "basics": true }, - "forms-deprecated": { - "title": "Forms", - "intro": "A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors.", - "basics": true, - "hide": true - }, - "dependency-injection": { "title": "Dependency Injection", "intro": "Angular's dependency injection system creates and delivers dependent services \"just-in-time\".", @@ -130,12 +123,6 @@ "intro": "Pipes transform displayed values within a template." }, - "router-deprecated": { - "title": "Routing & Navigation", - "intro": "Discover the basics of screen navigation with the Angular 2 Component Router.", - "hide": true - }, - "router": { "title": "Routing & Navigation", "intro": "Discover the basics of screen navigation with the Angular 2 Component Router." diff --git a/public/docs/dart/latest/guide/forms-deprecated.jade b/public/docs/dart/latest/guide/forms-deprecated.jade deleted file mode 100644 index f5711f49ee..0000000000 --- a/public/docs/dart/latest/guide/forms-deprecated.jade +++ /dev/null @@ -1,4 +0,0 @@ -include ../_util-fns - -:marked - This page has no Dart equivalent. Instead, see the [forms guide](forms.html). diff --git a/public/docs/dart/latest/guide/router-deprecated.jade b/public/docs/dart/latest/guide/router-deprecated.jade deleted file mode 100644 index d76267fce1..0000000000 --- a/public/docs/dart/latest/guide/router-deprecated.jade +++ /dev/null @@ -1,4 +0,0 @@ -include ../_util-fns - -:marked - This page has no Dart equivalent. Instead, see the [router guide](router.html). diff --git a/public/docs/js/latest/guide/_data.json b/public/docs/js/latest/guide/_data.json index d687f38e3a..724711f666 100644 --- a/public/docs/js/latest/guide/_data.json +++ b/public/docs/js/latest/guide/_data.json @@ -116,12 +116,6 @@ "intro": "Pipes transform displayed values within a template." }, - "router-deprecated": { - "title": "Router (Deprecated Beta)", - "intro": "The deprecated Beta Router.", - "hide": true - }, - "router": { "title": "Routing & Navigation", "intro": "Discover the basics of screen navigation with the Angular 2 router." diff --git a/public/docs/js/latest/guide/forms-deprecated.jade b/public/docs/js/latest/guide/forms-deprecated.jade deleted file mode 100644 index 69634ab56a..0000000000 --- a/public/docs/js/latest/guide/forms-deprecated.jade +++ /dev/null @@ -1,649 +0,0 @@ -include ../_util-fns - -.alert.is-important - :marked - This guide is using the deprecated forms API, which is disabled as of RC5, thus this sample only works up to RC4. - - We have created a new version using the new API here. - -:marked - We’ve all used a form to login, submit a help request, place an order, book a flight, - schedule a meeting and perform countless other data entry tasks. - Forms are the mainstay of business applications. - - Any seasoned web developer can slap together an HTML form with all the right tags. - It's more challenging to create a cohesive data entry experience that guides the - user efficiently and effectively through the workflow behind the form. - - *That* takes design skills that are, to be frank, well out of scope for this chapter. - - It also takes framework support for - **two-way data binding, change tracking, validation, and error handling** - ... which we shall cover in this chapter on Angular forms. - - We will build a simple form from scratch, one step at a time. Along the way we'll learn - - - How to build an Angular form with a component and template - - - The `ngModel` two-way data binding syntax for reading and writing values to input controls - - - The `ngControl` directive to track the change state and validity of form controls - - - The special CSS classes that `ngControl` adds to form controls and how we can use them to provide strong visual feedback - - - How to display validation errors to users and enable/disable form controls - - - How to share information across controls with template local variables - - Live Example - -.l-main-section -:marked - ## Template-Driven Forms - - Many of us will build forms by writing templates in the Angular [template syntax](./template-syntax.html) with - the form-specific directives and techniques described in this chapter. -.l-sub-section - :marked - That's not the only way to create a form but it's the way we'll cover in this chapter. -:marked - We can build almost any form we need with an Angular template — login forms, contact forms ... pretty much any business forms. - We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors, - conditionally enable or disable specific controls, trigger built-in visual feedback, and much more. - - It will be pretty easy because Angular handles many of the repetitive, boiler plate tasks we'd - otherwise wrestle with ourselves. - - We'll discuss and learn to build the following template-driven form: - -figure.image-display - img(src="/resources/images/devguide/forms/hero-form-1.png" width="400px" alt="Clean Form") - -:marked - Here at the *Hero Employment Agency* we use this form to maintain personal information about the - heroes in our stable. Every hero needs a job. It's our company mission to match the right hero with the right crisis! - - Two of the three fields on this form are required. Required fields have a green bar on the left to make them easy to spot. - - If we delete the hero name, the form displays a validation error in an attention grabbing style: - -figure.image-display - img(src="/resources/images/devguide/forms/hero-form-2.png" width="400px" alt="Invalid, Name Required") - -:marked - Note that the submit button is disabled and the "required" bar to the left of the input control changed from green to red. - -.l-sub-section - p We'll' customize the colors and location of the "required" bar with standard CSS. - -:marked - We will build this form in the following sequence of small steps - - 1. Create the `Hero` model class - 1. Create the component that controls the form - 1. Create a template with the initial form layout - 1. Add the **ngModel** directive to each form input control - 1. Add the **ngControl** directive to each form input control - 1. Add custom CSS to provide visual feedback - 1. Show and hide validation error messages - 1. Handle form submission with **ngSubmit** - 1. Disable the form’s submit button until the form is valid - -:marked - ## Setup - Create a new project folder (`angular2-forms`) and follow the steps in the [QuickStart](../quickstart.html). - - ## Create the Hero Model Class - - As users enter form data, we capture their changes and update an instance of a model. - We can't layout the form until we know what the model looks like. - - A model can be as simple as a "property bag" that holds facts about a thing of application importance. - That describes well our `Hero` class with its three required fields (`id`, `name`, `power`) - and one optional field (`alterEgo`). - - Create a new file in the app folder called `hero.js` and give it the following constructor: - -+makeExample('forms-deprecated/js/app/hero.js', null, 'app/hero.js') - -:marked - It's an anemic model with few requirements and no behavior. Perfect for our demo. - - The `alterEgo` is optional and the constructor lets us omit it by being the last argument. - - We can create a new hero like this: -code-example(format=""). - var myHero = new Hero(42, 'SkyDog', - 'Fetch any object at any distance', 'Leslie Rollover'); - console.log('My hero is called ' + myHero.name); // "My hero is called SkyDog" -:marked - We update the `` of the `index.html` to include this javascript file. - -+makeExample('forms-deprecated/js/index.html', 'scripts-hero', 'index.html (excerpt)')(format=".") - -.l-main-section -:marked - ## Create a Form component - - An Angular form has two parts: an HTML-based template and a code-based Component to handle data and user interactions. - - We begin with the Component because it states, in brief, what the Hero editor can do. - - Create a new file called `hero-form.component.js` and give it the following definition: - -+makeExample('forms-deprecated/js/app/hero-form.component.js', 'first', 'app/hero-form.component.js') - -:marked - There’s nothing special about this component, nothing form-specific, nothing to distinguish it from any component we've written before. - - Understanding this component requires only the Angular 2 concepts we’ve learned in previous chapters - - 1. We use the `ng.core` object from the Angular library as we usually do. - - 1. The `Component()` selector value of "hero-form" means we can drop this form in a parent template with a `` tag. - - 1. The `templateUrl` property points to a separate file for template HTML called `hero-form.component.html`. - - 1. We defined dummy data for `model` and `powers` as befits a demo. - Down the road, we can inject a data service to get and save real data - or perhaps expose these properties as [inputs and outputs](./template-syntax.html#inputs-outputs) for binding to a - parent component. None of this concerns us now and these future changes won't affect our form. - - 1. We threw in a `diagnostic` method at the end to return a JSON representation of our model. - It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later. - - Why don't we write the template inline in the component file as we often do - elsewhere in the Developer Guide? - - There is no “right” answer for all occasions. We like inline templates when they are short. - Most form templates won't be short. TypeScript and JavaScript files generally aren't the best place to - write (or read) large stretches of HTML and few editors are much help with files that have a mix of HTML and code. - We also like short files with a clear and obvious purpose like this one. - - We made a good choice to put the HTML template elsewhere. - We'll write that template in a moment. Before we do, we'll take a step back - and revise the `app.component.js` to make use of our new `HeroFormComponent`. - -:marked - Again we update the `` of the `index.html` to include the new javascript file. - -+makeExample('forms-deprecated/js/index.html', 'scripts-hero-form', 'index.html (excerpt)')(format=".") - -.l-main-section -:marked - ## Revise the *app.component.js* - - `app.component.js` is the application's root component. It will host our new `HeroFormComponent`. - - Replace the contents of the "QuickStart" version with the following: -+makeExample('forms-deprecated/js/app/app.component.js', null, 'app/app.component.js') - -:marked -.l-sub-section - :marked - There are only two changes: - - 1. The `template` is simply the new element tag identified by the component's `select` property. - - 1. The `directives` array tells Angular that our template depends upon the `HeroFormComponent` - which is itself a Directive (as are all Components). - -.l-main-section -:marked - ## Create an initial HTML Form Template - - Create a new template file called `hero-form.component.html` and give it the following definition: - -+makeExample('forms-deprecated/js/app/hero-form.component.html', 'start', 'app/hero-form.component.html') - -:marked - That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and - opening them up for user input in input boxes. - - The *Name* `` control has the HTML5 `required` attribute; - the *Alter Ego* `` control does not because `alterEgo` is optional. - - We've got a *Submit* button at the bottom with some classes on it. - - **We are not using Angular yet**. There are no bindings. No extra directives. Just layout. - - The `container`,`form-group`, `form-control`, and `btn` classes - come from [Twitter Bootstrap](http://getbootstrap.com/css/). Purely cosmetic. - We're using Bootstrap to gussy up our form. - Hey, what's a form without a little style! - -.callout.is-important - header Angular Forms Do Not Require A Style Library - :marked - Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or - the styles of any external library. Angular apps can use any CSS library - ... or none at all. - -:marked - Let's add the stylesheet. - -ol - li Open a terminal window in the application root folder and enter the command: - code-example(language="html" escape="html"). - npm install bootstrap --save - li Open index.html and add the following link to the <head>. - +makeExample('forms-deprecated/js/index.html', 'bootstrap')(format=".") -:marked -.l-main-section -:marked - ## Add Powers with ***ngFor** - Our hero may choose one super power from a fixed list of Agency-approved powers. - We maintain that list internally (in `HeroFormComponent`). - - We'll add a `select` to our - form and bind the options to the `powers` list using `NgFor`, - a technique we might have seen before in the [Displaying Data](./displaying-data.html) chapter. - - Add the following HTML *immediately below* the *Alter Ego* group. -+makeExample('forms-deprecated/js/app/hero-form.component.html', 'powers', 'app/hero-form.component.html (excerpt)')(format=".") - -:marked - We are repeating the `` tag for each power in the list of Powers. - The `#p` local template variable is a different power in each iteration; - we display its name using the interpolation syntax with the double-curly-braces. - -.l-main-section -:marked - ## Two-way data binding with ***ngModel** - Running the app right now would be disappointing. - -figure.image-display - img(src="/resources/images/devguide/forms/hero-form-3.png" width="400px" alt="Early form with no binding") -:marked - We don't see hero data because we are not binding to the `Hero` yet. - We know how to do that from earlier chapters. - [Displaying Data](./displaying-data.html) taught us Property Binding. - [User Input](./user-input.html) showed us how to listen for DOM events with an - Event Binding and how to update a component property with the displayed value. - - Now we need to display, listen, and extract at the same time. - - We could use those techniques again in our form. - Instead we'll introduce something new, the `NgModel` directive, that - makes binding our form to the model super-easy. - - Find the `` tag for the "Name" and update it like this - -+makeExample('forms-deprecated/js/app/hero-form.component.html', 'ngModel-1','app/hero-form.component.html (excerpt)')(format=".") - -.l-sub-section - :marked - We appended a diagnostic interpolation after the input tag - so we can see what we're doing. - We left ourselves a note to throw it way when we're done. - -:marked - Focus on the binding syntax: `[(ngModel)]="..."`. - - If we ran the app right now and started typing in the *Name* input box, - adding and deleting characters, we'd see them appearing and disappearing - from the interpolated text. - At some point it might look like this. -figure.image-display - img(src="/resources/images/devguide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action") -:marked - The diagnostic is evidence that we really are flowing values from the input box to the model and - back again. **That's two-way data binding!** - - Let's add similar `[(ngModel)]` bindings to *Alter Ego* and *Hero Power*. - We'll ditch the input box binding message - and add a new binding at the top to the component's `diagnostic` method. - Then we can confirm that two-way data binding works *for the entire Hero model*. - - After revision the core of our form should have three `[(ngModel)]` bindings that - look much like this: - -+makeExample('forms-deprecated/js/app/hero-form.component.html', 'ngModel-2', 'app/hero-form.component.html (excerpt)') - -:marked - If we ran the app right now and changed every Hero model property, the form might display like this: -figure.image-display - img(src="/resources/images/devguide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in super action") -:marked - The diagnostic near the top of the form - confirms that all of our changes are reflected in the model. - - **Delete** the `{{diagnostic()}}` binding at the top as it has served its purpose. - -.l-sub-section - :marked - ### Inside [(ngModel)] - *This section is an optional deep dive into [(ngModel)]. Not interested? Skip ahead!* - - The punctuation in the binding syntax, [()], is a good clue to what's going on. - - In a Property Binding, a value flows from the model to a target property on screen. - We identify that target property by surrounding its name in brackets, []. - This is a one-way data binding **from the model to the view**. - - In an Event Binding, we flow the value from the target property on screen to the model. - We identify that target property by surrounding its name in parentheses, (). - This is a one-way data binding in the opposite direction **from the view to the model**. - - No wonder Angular chose to combine the punctuation as [()] - to signify a two-way data binding and a **flow of data in both directions**. - - In fact, we can break the `NgModel` binding into its two separate modes - as we do in this re-write of the "Name" `` binding: - +makeExample('forms-deprecated/js/app/hero-form.component.html', 'ngModel-3','app/hero-form.component.html (excerpt)')(format=".") - - :marked -
The Property Binding should feel familiar. The Event Binding might seem strange. - - The `ngModelChange` is not an `` element event. - It is actually an event property of the `NgModel` directive. - When Angular sees a binding target in the form [(x)], - it expects the `x` directive to have an `x` input property and an `xChange` output property. - - The other oddity is the template expression, `model.name = $event`. - We're used to seeing an `$event` object coming from a DOM event. - The `ngModelChange` property doesn't produce a DOM event; it's an Angular `EventEmitter` - property that returns the input box value when it fires — which is precisely what - we should assign to the model's `name' property. - - Nice to know but is it practical? We almost always prefer `[(ngModel)]`. - We might split the binding if we had to do something special in - the event handling such as debounce or throttle the key strokes. - - Learn more about `NgModel` and other template syntax in the - [Template Syntax](./template-syntax.html) chapter. - -.l-main-section -:marked - ## Track change-state and validity with **ngControl** - - A form isn't just about data binding. We'd also like to know the state of the controls on our form. - The `NgControl` directive keeps track of control state for us. - -.callout.is-helpful - header NgControl requires Form - :marked - The `NgControl` is one of a family of `NgForm` directives that can only be applied to - a control within a ` tag. -:marked - Our application can ask an `NgControl` if the user touched the control, - if the value changed, or if the value became invalid. - - `NgControl` doesn't just track state; it updates the control with special - Angular CSS classes from the set we listed above. - We can leverage those class names to change the appearance of the - control and make messages appear or disappear. - - We'll explore those effects soon. Right now - we should **add `ngControl`to all three form controls**, - starting with the *Name* input box -+makeExample('forms-deprecated/js/app/hero-form.component.html', 'ngControl-1', 'app/hero-form.component.html (excerpt)')(format=".") -:marked - Be sure to assign a unique name to each `ngControl` directive. - -.l-sub-section - :marked - Angular registers controls under their `ngControl` names - with the `NgForm`. - We didn't add the `NgForm` directive explicitly but it's here - and we'll talk about it [later in this chapter](#ngForm). - -.l-main-section -:marked - ## Add Custom CSS for Visual Feedback - - `NgControl` doesn't just track state. - It updates the control with three classes that reflect the state. - -table - tr - th State - th Class if true - th Class if false - tr - td Control has been visited - td ng-touched - td ng-untouched - tr - td Control's value has changed - td ng-dirty - td ng-pristine - tr - td Control's value is valid - td ng-valid - td ng-invalid -:marked - Let's add a temporary [local template variable](./template-syntax.html#local-vars) named **spy** - to the "Name" `` tag and use the spy to display those classes. - -+makeExample('forms-deprecated/js/app/hero-form.component.html', 'ngControl-2','app/hero-form.component.html (excerpt)')(format=".") - -:marked - Now run the app and focus on the *Name* input box. - Follow the next four steps *precisely* - - 1. Look but don't touched - 1. Click in the input box, then click outside the text input box - 1. Add slashes to the end of the name - 1. Erase the name - - The actions and effects are as follows: -figure.image-display - img(src="/resources/images/devguide/forms/control-state-transitions-anim.gif" alt="Control State Transition") -:marked - We should be able to see the following four sets of class names and their transitions: -figure.image-display - img(src="/resources/images/devguide/forms/ng-control-class-changes.png" width="400px" alt="Control State Transitions") - -:marked - The (`ng-valid` | `ng-invalid`) pair are most interesting to us. We want to send a - strong visual signal when the data are invalid and we want to mark required fields. - - We realize we can do both at the same time with a colored bar on the left of the input box: - -figure.image-display - img(src="/resources/images/devguide/forms/validity-required-indicator.png" width="400px" alt="Invalid Form") - -:marked - We achieve this effect by adding two styles to a new `forms.css` file - that we add to our project as a sibling to `index.html`. - -+makeExample('forms-deprecated/js/forms.css',null,'forms.css')(format=".") -:marked - These styles select for the two Angular validity classes and the HTML 5 "required" attribute. - - We update the `` of the `index.html` to include this style sheet. -+makeExample('forms-deprecated/js/index.html', 'styles', 'index.html (excerpt)')(format=".") -:marked - ## Show and Hide Validation Error messages - - We can do better. - - The "Name" input box is required. Clearing it turns the bar red. That says *something* is wrong but we - don't know *what* is wrong or what to do about it. - We can leverage the `ng-invalid` class to reveal a helpful message. - - Here's the way it should look when the user deletes the name: -figure.image-display - img(src="/resources/images/devguide/forms/name-required-error.png" width="400px" alt="Name required") - -:marked - To achieve this effect we extend the `` tag with - 1. a [local template variable](./template-syntax.html#local-vars) - 1. the "*is required*" message in a nearby `
` which we'll display only if the control is invalid. - - Here's how we do it for the *name* input box: --var stylePattern = { otl: /(#name="form")|(.*div.*$)|(Name is required)/gm }; -+makeExample('forms-deprecated/js/app/hero-form.component.html', - 'name-with-error-msg', - 'app/hero-form.component.html (excerpt)', - stylePattern) -:marked - When we added the `ngControl` directive, we bound it to the model's `name` property. - Here we initialize a template local variable (`name`) with the value "ngForm" (`#name="ngForm"`). - Angular recognizes that syntax and re-sets the `name` local template variable to the - `ngControl` directive instance. - In other words, the `name` local template variable becomes a handle on the `ngControl` object - for this input box. - - Now we can control visibility of the "name" error message by binding the message `
` element's `hidden` property - to the `ngControl` object's `valid` property. The message is hidden while the control is valid; - the message is revealed when the control becomes invalid. - -.l-sub-section - :marked - ### The NgForm directive - We just set a template local variable with the value of an `NgForm` directive. - Why did that work? We didn't add the **[`NgForm`](../api/common/index/NgForm-directive.html) directive** explicitly. - - Angular added it surreptitiously, wrapping it around the `
` element - - The `NgForm` directive supplements the `form` element with additional features. - It collects `Controls` (elements identified by an `ngControl` directive) - and monitors their properties including their validity. - It also has its own `valid` property which is true only if every contained - control is valid. -:marked - The Hero *Alter Ego* is optional so we can leave that be. - - Hero *Power* selection is required. - We can add the same kind of error handling to the `` control has the HTML5 `required` attribute; - the *Alter Ego* `` control does not because `alterEgo` is optional. - - We've got a *Submit* button at the bottom with some classes on it. - - **We are not using Angular yet**. There are no bindings. No extra directives. Just layout. - - The `container`,`form-group`, `form-control`, and `btn` classes - come from [Twitter Bootstrap](http://getbootstrap.com/css/). Purely cosmetic. - We're using Bootstrap to gussy up our form. - Hey, what's a form without a little style! - -.callout.is-important - header Angular Forms Do Not Require A Style Library - :marked - Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or - the styles of any external library. Angular apps can use any CSS library - ... or none at all. - -:marked - Let's add the stylesheet. - -ol - li Open a terminal window in the application root folder and enter the command: - code-example(language="html" escape="html"). - npm install bootstrap --save - li Open index.html and add the following link to the <head>. - +makeExample('forms-deprecated/ts/index.html', 'bootstrap')(format=".") -:marked -.l-main-section -:marked - ## Add Powers with ***ngFor** - Our hero may choose one super power from a fixed list of Agency-approved powers. - We maintain that list internally (in `HeroFormComponent`). - - We'll add a `select` to our - form and bind the options to the `powers` list using `ngFor`, - a technique we might have seen before in the [Displaying Data](./displaying-data.html) chapter. - - Add the following HTML *immediately below* the *Alter Ego* group. -+makeExample('forms-deprecated/ts/app/hero-form.component.html', 'powers', 'app/hero-form.component.html (excerpt)')(format=".") - -:marked - We are repeating the `` tag for each power in the list of Powers. - The `p` template input variable is a different power in each iteration; - we display its name using the interpolation syntax with the double-curly-braces. - - -.l-main-section -:marked - ## Two-way data binding with **ngModel** - Running the app right now would be disappointing. - -figure.image-display - img(src="/resources/images/devguide/forms/hero-form-3.png" width="400px" alt="Early form with no binding") -:marked - We don't see hero data because we are not binding to the `Hero` yet. - We know how to do that from earlier chapters. - [Displaying Data](./displaying-data.html) taught us Property Binding. - [User Input](./user-input.html) showed us how to listen for DOM events with an - Event Binding and how to update a component property with the displayed value. - - Now we need to display, listen, and extract at the same time. - - We could use those techniques again in our form. - Instead we'll introduce something new, the `[(ngModel)]` syntax, that - makes binding our form to the model super-easy. - - Find the `` tag for the "Name" and update it like this - -+makeExample('forms-deprecated/ts/app/hero-form.component.html', 'ngModel-1','app/hero-form.component.html (excerpt)')(format=".") - -.l-sub-section - :marked - We appended a diagnostic interpolation after the input tag - so we can see what we're doing. - We left ourselves a note to throw it away when we're done. - -:marked - Focus on the binding syntax: `[(ngModel)]="..."`. - - If we ran the app right now and started typing in the *Name* input box, - adding and deleting characters, we'd see them appearing and disappearing - from the interpolated text. - At some point it might look like this. -figure.image-display - img(src="/resources/images/devguide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action") -:marked - The diagnostic is evidence that we really are flowing values from the input box to the model and - back again. **That's two-way data binding!** - - Let's add similar `[(ngModel)]` bindings to *Alter Ego* and *Hero Power*. - We'll ditch the input box binding message - and add a new binding at the top to the component's `diagnostic` property. - Then we can confirm that two-way data binding works *for the entire Hero model*. - - After revision the core of our form should have three `[(ngModel)]` bindings that - look much like this: - -+makeExample('forms-deprecated/ts/app/hero-form.component.html', 'ngModel-2', 'app/hero-form.component.html (excerpt)') - -:marked - If we ran the app right now and changed every Hero model property, the form might display like this: -figure.image-display - img(src="/resources/images/devguide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in super action") -:marked - The diagnostic near the top of the form - confirms that all of our changes are reflected in the model. - - **Delete** the `{{diagnostic}}` binding at the top as it has served its purpose. - -.l-sub-section - :marked - ### Inside [(ngModel)] - *This section is an optional deep dive into [(ngModel)]. Not interested? Skip ahead!* - - The punctuation in the binding syntax, [()], is a good clue to what's going on. - - In a Property Binding, a value flows from the model to a target property on screen. - We identify that target property by surrounding its name in brackets, []. - This is a one-way data binding **from the model to the view**. - - In an Event Binding, we flow the value from the target property on screen to the model. - We identify that target property by surrounding its name in parentheses, (). - This is a one-way data binding in the opposite direction **from the view to the model**. - - No wonder Angular chose to combine the punctuation as [()] - to signify a two-way data binding and a **flow of data in both directions**. - - In fact, we can break the `NgModel` binding into its two separate modes - as we do in this re-write of the "Name" `` binding: - +makeExample('forms-deprecated/ts/app/hero-form.component.html', 'ngModel-3','app/hero-form.component.html (excerpt)')(format=".") - - :marked -
The Property Binding should feel familiar. The Event Binding might seem strange. - - The `ngModelChange` is not an `` element event. - It is actually an event property of the `NgModel` directive. - When Angular sees a binding target in the form [(x)], - it expects the `x` directive to have an `x` input property and an `xChange` output property. - - The other oddity is the template expression, `model.name = $event`. - We're used to seeing an `$event` object coming from a DOM event. - The `ngModelChange` property doesn't produce a DOM event; it's an Angular `EventEmitter` - property that returns the input box value when it fires — which is precisely what - we should assign to the model's `name` property. - - Nice to know but is it practical? We almost always prefer `[(ngModel)]`. - We might split the binding if we had to do something special in - the event handling such as debounce or throttle the key strokes. - - Learn more about `NgModel` and other template syntax in the - [Template Syntax](./template-syntax.html) chapter. - -.l-main-section -:marked - ## Track change-state and validity with **ngControl** - - A form isn't just about data binding. We'd also like to know the state of the controls on our form. - - By setting `ngControl` we create a directive that can tell if the user touched the control, - if the value changed, or if the value became invalid. - - This directive doesn't just track state; it updates the control with special - Angular CSS classes from the set we listed above. - We can leverage those class names to change the appearance of the - control and make messages appear or disappear. - - We'll explore those effects soon. Right now - we should **add `ngControl` to all three form controls**, - starting with the *Name* input box -+makeExample('forms-deprecated/ts/app/hero-form.component.html', 'ngControl-1', 'app/hero-form.component.html (excerpt)')(format=".") -:marked - We set this particular `ngControl` to "name" which makes sense for our app. Any unique value will do. - -.l-sub-section - :marked - Internally Angular creates `Controls` and registers them under their `ngControl` names - with an `NgForm` directive that Angular attached to the `` tag. - We'll talk about `NgForm` [later in the chapter](#ngForm). - - The `ngControl` *attribute* in our template actually maps to the - [NgControlName](../api/common/index/NgControlName-directive.html) directive. - There is also a `NgControl` *abstract* directive which is *not the same thing*. - We often ignore this technical distinction and refer to `NgControlName` more conveniently (albeit incorrectly) as the *NgControl* directive. - - While we're under the hood, we might as well note that the `ngModel` in the - two-way binding syntax is now a property of the `NgControlName` directive. - The `NgModel` directive is no longer involved. We only need one directive to manage the DOM element - and there is no practical difference in the way either directive handles data binding. - -.l-main-section -:marked - ## Add Custom CSS for Visual Feedback - - The *NgControl* directive doesn't just track state. - It updates the control with three classes that reflect the state. - -table - tr - th State - th Class if true - th Class if false - tr - td Control has been visited - td ng-touched - td ng-untouched - tr - td Control's value has changed - td ng-dirty - td ng-pristine - tr - td Control's value is valid - td ng-valid - td ng-invalid -:marked - Let's add a temporary [template reference variable](./template-syntax.html#ref-vars) named **spy** - to the "Name" `` tag and use the spy to display those classes. - -+makeExample('forms-deprecated/ts/app/hero-form.component.html', 'ngControl-2','app/hero-form.component.html (excerpt)')(format=".") - -:marked - Now run the app and focus on the *Name* input box. - Follow the next four steps *precisely* - - 1. Look but don't touch - 1. Click in the input box, then click outside the text input box - 1. Add slashes to the end of the name - 1. Erase the name - - The actions and effects are as follows: -figure.image-display - img(src="/resources/images/devguide/forms/control-state-transitions-anim.gif" alt="Control State Transition") -:marked - We should be able to see the following four sets of class names and their transitions: -figure.image-display - img(src="/resources/images/devguide/forms/ng-control-class-changes.png" width="400px" alt="Control State Transitions") - -:marked - The (`ng-valid` | `ng-invalid`) pair are most interesting to us. We want to send a - strong visual signal when the data are invalid and we want to mark required fields. - - We realize we can do both at the same time with a colored bar on the left of the input box: - -figure.image-display - img(src="/resources/images/devguide/forms/validity-required-indicator.png" width="400px" alt="Invalid Form") - -:marked - We achieve this effect by adding two styles to a new `forms.css` file - that we add to our project as a sibling to `index.html`. - -+makeExample('forms-deprecated/ts/forms.css',null,'forms.css')(format=".") -:marked - These styles select for the two Angular validity classes and the HTML 5 "required" attribute. - - We update the `` of the `index.html` to include this style sheet. -+makeExample('forms-deprecated/ts/index.html', 'styles', 'index.html (excerpt)')(format=".") -:marked - ## Show and Hide Validation Error messages - - We can do better. - - The "Name" input box is required. Clearing it turns the bar red. That says *something* is wrong but we - don't know *what* is wrong or what to do about it. - We can leverage the `ng-invalid` class to reveal a helpful message. - - Here's the way it should look when the user deletes the name: -figure.image-display - img(src="/resources/images/devguide/forms/name-required-error.png" width="400px" alt="Name required") - -:marked - To achieve this effect we extend the `` tag with - 1. a [template reference variable](./template-syntax.html#ref-vars) - 1. the "*is required*" message in a nearby `
` which we'll display only if the control is invalid. - - Here's how we do it for the *name* input box: -+makeExample('forms-deprecated/ts/app/hero-form.component.html', - 'name-with-error-msg', - 'app/hero-form.component.html (excerpt)')(format=".") -:marked - We need a template reference variable to access the input box's Angular control from within the template. - Here we created a variable called `name` and gave it the value "ngForm". -.l-sub-section - :marked - Why "ngForm"? - A directive's [exportAs](../api/core/index/DirectiveMetadata-class.html#!#exportAs) property - tells Angular how to link the reference variable to the directive. - We set `name` to `ngForm` because the `NgControlName` directive's `exportAs` property happens to be "ngForm". - - This seems unintuitive at first until we realize that *all* control directives in the - Angular form family — including `NgForm`, `NgModel`, `NgControlName` and `NgControlGroup` — *exportAs* "ngForm" - and we only ever apply *one* of these directives to an element tag. - Consistency rules! - - Now we can control visibility of the "name" error message by binding properties of the `name` control to the message `
` element's `hidden` property. -+makeExample('forms-deprecated/ts/app/hero-form.component.html', - 'hidden-error-msg', - 'app/hero-form.component.html (excerpt)') -:marked - In this example, we hide the message when the control is valid or pristine; - pristine means the user hasn't changed the value since it was displayed in this form. - - This user experience is the developer's choice. Some folks want to see the message at all times. - If we ignore the `pristine` state, we would hide the message only when the value is valid. - If we arrive in this component with a new (blank) hero or an invalid hero, - we'll see the error message immediately, before we've done anything. - - Some folks find that behavior disconcerting. They only want to see the message when the user makes an invalid change. - Hiding the message while the control is "pristine" achieves that goal. - We'll see the significance of this choice when we [add a new hero](#new-hero) to the form. - - The Hero *Alter Ego* is optional so we can leave that be. - - Hero *Power* selection is required. - We can add the same kind of error handling to the `