diff --git a/public/docs/_examples/forms/ts/app/hero-form.component.html b/public/docs/_examples/forms/ts/app/hero-form.component.html index 19d717cd5b..a44c9e9ee1 100644 --- a/public/docs/_examples/forms/ts/app/hero-form.component.html +++ b/public/docs/_examples/forms/ts/app/hero-form.component.html @@ -1,20 +1,19 @@ - - + +
-
+

Hero Form

- - +
+ #name="ngModel">
@@ -27,7 +26,7 @@
+ [(ngModel)]="model.alterEgo" name="alterEgo">
@@ -35,7 +34,7 @@
@@ -185,25 +184,25 @@
- - TODO: remove this: {{model.name}} + TODO: remove this: {{model.name}}
- TODO: remove this: {{model.name}} + (ngModelChange)="model.name = $event"> + TODO: remove this: {{model.name}}
+ #spy>
TODO: remove this: {{spy.className}} diff --git a/public/docs/_examples/forms/ts/app/hero-form.component.ts b/public/docs/_examples/forms/ts/app/hero-form.component.ts index 9c86266ce3..b2db8aaafd 100644 --- a/public/docs/_examples/forms/ts/app/hero-form.component.ts +++ b/public/docs/_examples/forms/ts/app/hero-form.component.ts @@ -1,6 +1,5 @@ // #docplaster -// #docregion -// #docregion first, final +// #docregion , v1, final import { Component } from '@angular/core'; import { Hero } from './hero'; @@ -26,21 +25,29 @@ export class HeroFormComponent { // #enddocregion final // TODO: Remove this when we're done get diagnostic() { return JSON.stringify(this.model); } - // #enddocregion first + // #enddocregion v1 - // #docregion final - // #docregion new-hero + // #docregion final, new-hero newHero() { this.model = new Hero(42, '', ''); } - // #enddocregion new-hero - // #enddocregion final + // #enddocregion final, new-hero + + skyDog(): Hero { + // #docregion SkyDog + let 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" + // #enddocregion SkyDog + return myHero; + } + //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(heroForm)}} showFormControls(form: any) { - return form && form.controls['name'] && // #docregion form-controls form.controls['name'].value; // Dr. IQ @@ -49,6 +56,5 @@ export class HeroFormComponent { ///////////////////////////// - // #docregion first, final + // #docregion v1, final } -// #enddocregion first, final diff --git a/public/docs/ts/latest/guide/forms.jade b/public/docs/ts/latest/guide/forms.jade index 7bbcc9ae5e..4d9c97f970 100644 --- a/public/docs/ts/latest/guide/forms.jade +++ b/public/docs/ts/latest/guide/forms.jade @@ -2,7 +2,7 @@ include ../_util-fns :marked We’ve all used a form to log in, submit a help request, place an order, book a flight, - schedule a meeting and perform countless other data entry tasks. + 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. @@ -15,91 +15,89 @@ include ../_util-fns **two-way data binding, change tracking, validation, and error handling** ... which we shall cover in this guide on Angular forms. - We will build a simple form from scratch, one step at a time. Along the way we'll learn how to + 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 - - - two-way data bind with `[(ngModel)]` syntax for reading and writing values to input controls - - - track the change state and validity of form controls using `ngModel` in combination with a form - - - provide strong visual feedback using special CSS classes that track the state of the controls - - - display validation errors to users and enable/disable form controls - - - use [template reference variables](./template-syntax.html#ref-vars) for sharing information among HTML elements + - Build an Angular form with a component and template + - Use `ngModel` to create two-way data bindings for reading and writing input control values + - Track state changes and the validity of form controls + - Provide visual feedback using special CSS classes that track the state of the controls + - Display validation errors to users and enable/disable form controls + - Share information across HTML elements using template reference variables Run the . .l-main-section :marked - ## Template-Driven Forms + ## 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 guide. + .l-sub-section :marked That's not the only way to create a form but it's the way we'll cover in this guide. :marked - We can build almost any form we need with an Angular template — login forms, contact forms ... pretty much any business forms. + We can build almost any form we need with an Angular template — login forms, contact forms, pretty much any business form. 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 + It will be pretty easy because Angular handles many of the repetitive, boilerplate tasks we'd otherwise wrestle with ourselves. - We'll discuss and learn to build the following template-driven form: + We'll discuss and learn to build a template-driven form that looks like this: 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! + Here at the *Hero Employment Agency* we use this form to maintain personal information about heroes. + 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: + 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. + 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'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 + We'll build this form in 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. Bind data properties to each form input control with the `ngModel` two-way data binding syntax - 1. Add the `name` attribute 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 + 1. Create the `Hero` model class. + 1. Create the component that controls the form. + 1. Create a template with the initial form layout. + 1. Bind data properties to each form control using the `ngModel` two-way data binding syntax. + 1. Add a `name` attribute 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 + Follow the [setup](setup.html) instructions for creating a new project named angular-forms. - ## Create the Hero Model Class + ## 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. + As users enter form data, we'll capture their changes and update an instance of a model. + We can't lay out 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.ts` and give it the following class definition: + In the `!{_appDir}` directory, create the following file with the given content: -+makeExample('forms/ts/app/hero.ts', null, 'app/hero.ts') ++makeExample('app/hero.ts') :marked It's an anemic model with few requirements and no behavior. Perfect for our demo. @@ -107,49 +105,40 @@ figure.image-display The TypeScript compiler generates a public field for each `public` constructor parameter and assigns the parameter’s value to that field automatically when we create new heroes. - The `alterEgo` is optional and the constructor lets us omit it; note the (?) in `alterEgo?`. + The `alterEgo` is optional, so the constructor lets us omit it; note the (?) in `alterEgo?`. We can create a new hero like this: -code-example(format=""). - let 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 + ++makeExcerpt('app/hero-form.component.ts', 'SkyDog', '') .l-main-section :marked - ## Create a Form component + ## Create a form component An Angular form has two parts: an HTML-based _template_ and a component _class_ to handle data and user interactions programmatically. We begin with the class because it states, in brief, what the hero editor can do. - Create a new file called `hero-form.component.ts` and give it the following definition: + Create the following file with the given content: -+makeExample('forms/ts/app/hero-form.component.ts', 'first', 'app/hero-form.component.ts') ++makeExcerpt('app/hero-form.component.ts', 'v1') :marked - There’s nothing special about this component, nothing form-specific, nothing to distinguish it from any component we've written before. + 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 concepts we’ve learned in previous guides - - 1. We import the `Component` decorator from the Angular library as we usually do. - - 1. We import the `Hero` model we just created. + Understanding this component requires only the Angular concepts covered in previous guides. + 1. The code imports the Angular core library, and the `Hero` model we just created. 1. The `@Component` selector value of "hero-form" means we can drop this form in a parent template with a `` tag. - 1. The `moduleId: module.id` property sets the base for module-relative loading of the `templateUrl`. - - 1. The `templateUrl` property points to a separate file for the template HTML called `hero-form.component.html`. - - 1. We defined dummy data for `model` and `powers` as befits a demo. + 1. The `templateUrl` property points to a separate file for the template 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 + 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` property at the end to return a JSON representation of our model. + 1. We threw in a `diagnostic` property 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 the separate template file? @@ -168,7 +157,7 @@ code-example(format=""). .l-main-section :marked - ## Revise the *app.module.ts* + ## Revise *app.module.ts* `app.module.ts` defines the application's root module. In it we identify the external modules we'll use in our application and declare the components that belong to this module, such as our `HeroFormComponent`. @@ -199,27 +188,29 @@ code-example(format=""). .l-main-section :marked - ## Revise the *app.component.ts* + ## Revise *app.component.ts* - `app.component.ts` is the application's root component. It will host our new `HeroFormComponent`. + `AppComponent` is the application's root component. It will host our new `HeroFormComponent`. Replace the contents of the "QuickStart" version with the following: -+makeExample('forms/ts/app/app.component.ts', null, 'app/app.component.ts') + ++makeExample('app/app.component.ts') :marked .l-sub-section :marked - There is only one change. + There are only two changes. The `template` is simply the new element tag identified by the component's `selector` property. This will display the hero form when the application component is loaded. + We've also dropped the `name` field from the class body. .l-main-section :marked - ## Create an initial HTML Form Template + ## Create an initial HTML form template - Create a new template file called `hero-form.component.html` and give it the following definition: + Create the new template file with the following contents: -+makeExample('forms/ts/app/hero-form.component.html', 'start', 'app/hero-form.component.html') ++makeExample('app/hero-form.component.html', 'start') :marked That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and @@ -230,45 +221,47 @@ code-example(format=""). We've got a *Submit* button at the bottom with some classes on it for styling. - **We are not using Angular yet**. There are no bindings. No extra directives. Just layout. + **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 give the form a little style! .callout.is-important - header Angular Forms Do Not Require A Style Library + 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. + the styles of any external library. Angular apps can use any CSS library, or none at all. :marked - Let's add the stylesheet. Open index.html and add the following link to the <head>. -+makeExample('forms/ts/index.html', 'bootstrap')(format=".") + Let's add the stylesheet. Open `index.html` and add the following link to the ``: + ++makeExcerpt('index.html', 'bootstrap') -:marked .l-main-section :marked - ## Add Powers with ***ngFor** - Our hero may choose one super power from a fixed list of Agency-approved powers. + ## Add powers with _*ngFor_ + + Our hero must 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 seen previously in the [Displaying Data](./displaying-data.html) guide. - Add the following HTML *immediately below* the *Alter Ego* group. -+makeExample('forms/ts/app/hero-form.component.html', 'powers', 'app/hero-form.component.html (excerpt)')(format=".") + Add the following HTML *immediately below* the *Alter Ego* group: + ++makeExcerpt('app/hero-form.component.html (powers)') :marked - We are repeating the `` tag for each power in the list of Powers. + This code repeats the `