From 9615e59e785f25ffea7e2271704f89e57cf61084 Mon Sep 17 00:00:00 2001 From: Carol Franger Date: Fri, 27 Jan 2017 18:19:49 -0800 Subject: [PATCH 01/11] Content edits in the Angular 2 "Forms" page. --- public/docs/ts/latest/guide/forms.jade | 409 +++++++++++++------------ 1 file changed, 209 insertions(+), 200 deletions(-) diff --git a/public/docs/ts/latest/guide/forms.jade b/public/docs/ts/latest/guide/forms.jade index 4d9c97f970..b64d69b4c7 100644 --- a/public/docs/ts/latest/guide/forms.jade +++ b/public/docs/ts/latest/guide/forms.jade @@ -1,83 +1,90 @@ 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. Forms are the mainstay of business applications. + You use forms to log in, submit a help request, place an order, book a flight, + schedule a meeting, and perform countless other data-entry tasks. - 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 + Any seasoned web developer can create 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 guide. + *That* takes design skills that are, to be frank, well out of scope for this page. It also takes framework support for - **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: - - - 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 . + *two-way data binding, change tracking, validation, and error handling*, + which is covered in this page on Angular forms. + + + You'll build a simple form from scratch, one step at a time. Along the way you'll learn how to: + + - 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. + + You can run the in Plunker and download the code from there. .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 guide. + You can build forms by writing templates in the Angular [template syntax](./template-syntax.html) with + the form-specific directives and techniques described in this page. .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. + That's not the only way to create a form but it's the way that's covered in this page. +// CF: Is this note necessary? :marked - 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, + You can build almost any form with an Angular template—login forms, contact forms, and pretty much any business form. + You 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, boilerplate tasks we'd - otherwise wrestle with ourselves. + Angular makes the process easy by handling many of the repetitive, boilerplate tasks you'd + otherwise wrestle with yourself. - We'll discuss and learn to build a template-driven form that looks like this: + You'll 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 heroes. - Every hero needs a job. It's our company mission to match the right hero with the right crisis! + The *Hero Employment Agency* uses this form to maintain personal information about heroes. + Every hero needs a job. It's the 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 you 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 changes from green to red. .l-sub-section :marked - We'll customize the colors and location of the "required" bar with standard CSS. + You can customize the colors and location of the "required" bar with standard CSS. :marked - We'll build this form in small steps: + You'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 control using the `ngModel` two-way data binding syntax. - 1. Add a `name` attribute to each form input control. + 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. 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 @@ -88,11 +95,11 @@ figure.image-display ## Create the Hero model class - 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. + As users enter form data, you'll capture their changes and update an instance of a model. + You can't lay out the form until you 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`) + That describes well the `Hero` class with its three required fields (`id`, `name`, `power`) and one optional field (`alterEgo`). In the `!{_appDir}` directory, create the following file with the given content: @@ -100,14 +107,14 @@ figure.image-display +makeExample('app/hero.ts') :marked - It's an anemic model with few requirements and no behavior. Perfect for our demo. + It's an anemic model with few requirements and no behavior. Perfect for the demo. 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. + automatically assigns the parameter’s value to that field when you create heroes. - The `alterEgo` is optional, so the constructor lets us omit it; note the (?) in `alterEgo?`. + The `alterEgo` is optional, so the constructor lets you omit it; note the question mark (?) in `alterEgo?`. - We can create a new hero like this: + You can create a new hero like this: +makeExcerpt('app/hero-form.component.ts', 'SkyDog', '') @@ -117,7 +124,7 @@ figure.image-display 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. + Begin with the class because it states, in brief, what the hero editor can do. Create the following file with the given content: @@ -125,45 +132,46 @@ figure.image-display :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 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. - 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` 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. + nothing to distinguish it from any component you've written before. + + Understanding this component requires only the Angular concepts covered in previous pages. + + - The code imports the Angular core library and the `Hero` model you just created. + - The `@Component` selector value of "hero-form" means you can drop this form in a parent template with a `` tag. + - The `moduleId: module.id` property sets the base for module-relative loading of the `templateUrl`. + - The `templateUrl` property points to a separate file for the template HTML. + - You defined dummy data for `model` and `powers`, as befits a demo. + Down the road, you can inject a data service to get and save real data + or perhaps expose these properties as inputs and outputs + (see [Input and output properties](./template-syntax.html#inputs-outputs) on the + [Template Syntax](./template-syntax.html) page) for binding to a + parent component. This is not a concern now and these future changes won't affect the form. + - You added a `diagnostic` property to return a JSON representation of the model. + It'll help you see what you're doing during development; you've left yourself a cleanup note to discard it later. ### Why the separate template file? - Why don't we write the template inline in the component file as we often do elsewhere? + Why don't you write the template inline in the component file as you often do elsewhere? - 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. + There is no "right" answer for all occasions. Inline templates are useful when they are short. + Most form templates aren't short. TypeScript and JavaScript files generally aren't the best place to + write (or read) large stretches of HTML, and few editors help with files that have a mix of HTML and code. + - Form templates tend to be quite large even when displaying a small number of fields + Form templates tend to be large, even when displaying a small number of fields, so it's usually best to put the HTML template in a separate file. - We'll write that template file in a moment. Before we do, we'll take a step back - and revise the `app.module.ts` and `app.component.ts` to make use of the new `HeroFormComponent`. + You'll write that template file in a moment. First, + revise the `app.module.ts` and `app.component.ts` to make use of the new `HeroFormComponent`. .l-main-section :marked ## 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`. + `app.module.ts` defines the application's root module. In it you identify the external modules you'll use in the application + and declare the components that belong to this module, such as the `HeroFormComponent`. - Because template-driven forms are in their own module, we need to add the `FormsModule` to the array of - `imports` for our application module before we can use forms. + Because template-driven forms are in their own module, you need to add the `FormsModule` to the array of + `imports` for the application module before you can use forms. Replace the contents of the "QuickStart" version with the following: +makeExample('forms/ts/app/app.module.ts', null, 'app/app.module.ts') @@ -173,24 +181,26 @@ figure.image-display :marked There are three changes: - 1. We import `FormsModule` and our new `HeroFormComponent`. + 1. You import `FormsModule` and the new `HeroFormComponent`. - 1. We add the `FormsModule` to the list of `imports` defined in the `ngModule` decorator. This gives our application + 1. You add the `FormsModule` to the list of `imports` defined in the `ngModule` decorator. This gives the application access to all of the template-driven forms features, including `ngModel`. - 1. We add the `HeroFormComponent` to the list of `declarations` defined in the `ngModule` decorator. This makes + 1. You add the `HeroFormComponent` to the list of `declarations` defined in the `ngModule` decorator. This makes the `HeroFormComponent` component visible throughout this module. .alert.is-important :marked - If a component, directive, or pipe belongs to a module in the `imports` array, ​_DON'T_​ re-declare it in the `declarations` array. - If you wrote it and it should belong to this module, ​_DO_​ declare it in the `declarations` array. + If a component, directive, or pipe belongs to a module in the `imports` array, ​_don't_​ re-declare it in the `declarations` array. + If you wrote it and it should belong to this module, ​_do_​ declare it in the `declarations` array. +// CF: Not sure I understand what "If you wrote it" means. Does it matter who wrote it? + What if someone else wrote the component but it should belong to this module? Should I declare it or not? .l-main-section :marked ## Revise *app.component.ts* - `AppComponent` is the application's root component. It will host our new `HeroFormComponent`. + `AppComponent` is the application's root component. It will host the new `HeroFormComponent`. Replace the contents of the "QuickStart" version with the following: @@ -201,40 +211,40 @@ figure.image-display :marked 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. + This displays the hero form when the application component is loaded. + You've also dropped the `name` field from the class body. .l-main-section :marked ## Create an initial HTML form template - Create the new template file with the following contents: + Create the template file with the following contents: +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 + The language is simply HTML5. You'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 for styling. + You added 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. + *You're not using Angular yet*. There are no bindings or 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! + come from [Twitter Bootstrap](http://getbootstrap.com/css/). These classes are purely cosmetic. + Bootstrap gives the form a little style. .callout.is-important - header Angular forms do not require a style library + header Angular forms don't 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 ``: + To add the stylesheet, open `index.html` and add the following link to the ``: +makeExcerpt('index.html', 'bootstrap') @@ -242,12 +252,12 @@ figure.image-display :marked ## 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`). + The hero must choose one superpower from a fixed list of agency-approved powers. + You maintain that list internally (in `HeroFormComponent`). - We'll add a `select` to our + You'll add a `select` to the form and bind the options to the `powers` list using `ngFor`, - a technique seen previously in the [Displaying Data](./displaying-data.html) guide. + a technique seen previously in the [Displaying Data](./displaying-data.html) page. Add the following HTML *immediately below* the *Alter Ego* group: @@ -256,7 +266,7 @@ figure.image-display :marked This code repeats the `