docs(forms): revise prose for form.reset (#2853)

This commit is contained in:
Ward Bell 2016-11-21 18:23:28 -08:00 committed by GitHub
parent a7525721c0
commit 434308ab1b
4 changed files with 66 additions and 77 deletions

View File

@ -36,7 +36,7 @@
required
[(ngModel)]="model.power" name="power"
#power="ngModel" >
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
<option *ngFor="let pow of powers" [value]="pow">{{pow}}</option>
</select>
<div [hidden]="power.valid || power.pristine" class="alert alert-danger">
Power is required
@ -46,12 +46,18 @@
<!-- #docregion submit-button -->
<button type="submit" class="btn btn-default" [disabled]="!heroForm.form.valid">Submit</button>
<!-- #enddocregion submit-button -->
<!-- #docregion new-hero-button -->
<!-- #docregion new-hero-button-form-reset -->
<button type="button" class="btn btn-default" (click)="newHero(); heroForm.reset()">New Hero</button>
<!-- #enddocregion new-hero-button -->
<!-- #enddocregion new-hero-button-form-reset -->
<!-- #enddocregion final -->
<i>with</i> reset
&nbsp;&nbsp;
<!-- #docregion new-hero-button-no-reset -->
<button type="button" class="btn btn-default" (click)="newHero()">New Hero</button>
<!-- #enddocregion new-hero-button-no-reset -->
<i>without</i> reset
<!-- NOT SHOWN IN DOCS -->
<div>
<hr>
@ -126,7 +132,7 @@
<div class="form-group">
<label for="power">Hero Power</label>
<select class="form-control" id="power" required>
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
<option *ngFor="let pow of powers" [value]="pow">{{pow}}</option>
</select>
</div>
@ -165,7 +171,7 @@
<select class="form-control" id="power"
required
[(ngModel)]="model.power" name="power">
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
<option *ngFor="let pow of powers" [value]="pow">{{pow}}</option>
</select>
</div>
@ -178,12 +184,12 @@
<!-- EXTRA MATERIAL FOR DOCUMENTATION -->
<hr>
<!-- #docregion ngModel-1-->
<!-- #docregion ngModelName-1 -->
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name">
TODO: remove this: {{model.name}}
<!-- #enddocregion ngModel-1-->
<!-- #enddocregion ngModelName-1 -->
<hr>
<!-- #docregion ngModel-3-->
<input type="text" class="form-control" id="name"
@ -193,16 +199,6 @@
TODO: remove this: {{model.name}}
<!-- #enddocregion ngModel-3-->
<hr>
<!-- #docregion form-reset -->
<button type="button" class="btn btn-default" (click)="newHero(); heroForm.reset()">New Hero</button>
<!-- #enddocregion form-reset -->
<!-- #docregion ngModelName-1 -->
<input type="text" class="form-control" id="name"
required
[(ngModel)]="model.name" name="name" >
<!-- #enddocregion ngModelName-1 -->
<hr>
<!-- #docregion ngModelName-2 -->
<input type="text" class="form-control" id="name"
required

View File

@ -30,11 +30,9 @@ export class HeroFormComponent {
// #docregion final
// #docregion new-hero
// #docregion new-hero-v1
newHero() {
this.model = new Hero(42, '', '');
}
// #enddocregion new-hero-v1
// #enddocregion new-hero
// #enddocregion final
//////// NOT SHOWN IN DOCS ////////

View File

@ -2,7 +2,4 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
// Compiles the module (asynchronously) with the runtime compiler
// which generates a compiled module factory in memory.
// Then bootstraps with that factory, targeting the browser.
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -9,11 +9,11 @@ include ../_util-fns
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.
*That* takes design skills that are, to be frank, well out of scope for this guide.
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.
... 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
@ -36,10 +36,10 @@ include ../_util-fns
## 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.
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 chapter.
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 &mdash; 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,
@ -122,9 +122,9 @@ code-example(format="").
: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.
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:
@ -133,7 +133,7 @@ code-example(format="").
:marked
Theres 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 weve learned in previous chapters
Understanding this component requires only the Angular concepts weve learned in previous guides
1. We import the `Component` decorator from the Angular library as we usually do.
@ -153,17 +153,19 @@ code-example(format="").
1. We threw in a `diagnostic` property 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?
### Why the separate template file?
Why don't we write the template inline in the component file as we 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.
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.module.ts` and `app.component.ts` to make use of our new `HeroFormComponent`.
Form templates tend to be quite 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`.
.l-main-section
:marked
@ -193,7 +195,7 @@ code-example(format="").
.alert.is-important
:marked
If a component, directive, or pipe belongs to a module in the `imports` array, _DON'T_ 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.
.l-main-section
@ -208,9 +210,8 @@ code-example(format="").
:marked
.l-sub-section
:marked
There is only one change:
1. The `template` is simply the new element tag identified by the component's `selector` property.
There is only one change.
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.
.l-main-section
@ -234,8 +235,7 @@ code-example(format="").
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!
We're using Bootstrap to give the form a little style!
.callout.is-important
header Angular Forms Do Not Require A Style Library
@ -262,27 +262,27 @@ ol
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.
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=".")
:marked
We are repeating the `<options>` tag for each power in the list of Powers.
The `p` template input variable is a different power in each iteration;
The `pow` template input variable is a different power in each iteration;
we display its name using the interpolation syntax with the double-curly-braces.
<a id="ngModel"></a>
.l-main-section
:marked
## Two-way data binding with **ngModel**
## 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.
We know how to do that from earlier guides.
[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.
@ -295,7 +295,7 @@ figure.image-display
Find the `<input>` tag for the "Name" and update it like this
+makeExample('forms/ts/app/hero-form.component.html', 'ngModel-1','app/hero-form.component.html (excerpt)')(format=".")
+makeExample('forms/ts/app/hero-form.component.html', 'ngModelName-1','app/hero-form.component.html (excerpt)')(format=".")
.l-sub-section
:marked
@ -324,13 +324,13 @@ figure.image-display
:marked
Internally Angular creates `FormControls` and registers them with an `NgForm` directive that Angular
attached to the `<form>` tag. Each `FormControl` is registered under the name we assigned to the `name` attribute.
We'll talk about `NgForm` [later in this chapter](#ngForm).
We'll talk about `NgForm` [later in this guide](#ngForm).
:marked
Let's add similar `[(ngModel)]` bindings and `name` attributes 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*.
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 and `name` attributes that
look much like this:
@ -344,7 +344,7 @@ figure.image-display
- Each input element has a `name` property that is required by Angular Forms to register the control with the form.
:marked
If we ran the app right now and changed every Hero model property, the form might display like this:
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
@ -355,7 +355,7 @@ figure.image-display
.l-sub-section
:marked
### Inside [(ngModel)]
### Inside _[(ngModel)]_
*This section is an optional deep dive into [(ngModel)]. Not interested? Skip ahead!*
The punctuation in the binding syntax, <span style="font-family:courier"><b>[()]</b></span>, is a good clue to what's going on.
@ -394,11 +394,11 @@ figure.image-display
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.
[Template Syntax](./template-syntax.html) guide.
.l-main-section
:marked
## Track change-state and validity with **ngModel**
## Track change-state and validity with **_ngModel_**
A form isn't just about data binding. We'd also like to know the state of the controls on our form.
@ -509,7 +509,7 @@ figure.image-display
Now we can control visibility of the "name" error message by binding properties of the `name` control to the message `<div>` element's `hidden` property.
+makeExample('forms/ts/app/hero-form.component.html',
'hidden-error-msg',
'app/hero-form.component.html (excerpt)')
'app/hero-form.component.html (excerpt)')(format='.')
: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.
@ -523,7 +523,7 @@ figure.image-display
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.
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 `<select>` if we want
@ -536,14 +536,14 @@ figure.image-display
:marked
## Add a hero and reset the form
We'd like to add a new hero in this form.
We place a "New Hero" button at the bottom of the form and bind its click event to a component method.
We place a "New Hero" button at the bottom of the form and bind its click event to a `newHero` component method.
+makeExample('forms/ts/app/hero-form.component.html',
'new-hero-button',
'new-hero-button-no-reset',
'app/hero-form.component.html (New Hero button)')
:marked
+makeExample('forms/ts/app/hero-form.component.ts',
'new-hero-v1',
'app/hero-form.component.ts (New Hero method - v1)')(format=".")
'new-hero',
'app/hero-form.component.ts (New Hero method)')(format=".")
:marked
Run the application again, click the *New Hero* button, and the form clears.
The *required* bars to the left of the input box are red, indicating invalid `name` and `power` properties.
@ -551,28 +551,26 @@ figure.image-display
The error messages are hidden because the form is pristine; we haven't changed anything yet.
Enter a name and click *New Hero* again.
This time we see an error message! Why? We don't want that when we display a new (empty) hero.
The app displays a **_Name is required_** error message!
We don't want error messages when we create a new (empty) hero.
Why are we getting one now?
Inspecting the element in the browser tools reveals that the *name* input box is no longer pristine.
Replacing the hero *did not restore the pristine state* of the control.
.l-sub-section
:marked
Upon reflection, we realize that Angular cannot distinguish between
replacing the entire hero and clearing the `name` property programmatically.
Angular makes no assumptions and leaves the control in its current, dirty state.
:marked
We'll have to reset the form controls.
We call the `reset()` method of the form after calling the `newHero()` method.
Inspecting the element in the browser tools reveals that the *name* input box is _no longer pristine_.
The form remembers that we entered a name before clicking *New Hero*.
Replacing the hero object *did not restore the pristine state* of the form controls.
We have to clear all of the flags imperatively which we can do
by calling the form's `reset()` method after calling the `newHero()` method.
+makeExample('forms/ts/app/hero-form.component.html',
'form-reset',
'new-hero-button-form-reset',
'app/hero-form.component.html (Reset the form)')
:marked
This will reset the `heroForm` and its status by clicking "New Hero".
Now clicking "New Hero" both resets the form and its control flags.
:marked
.l-main-section
:marked
## Submit the form with **ngSubmit**
## Submit the form with **_ngSubmit_**
The user should be able to submit this form after filling it in.
The Submit button at the bottom of the form
does nothing on its own but it will
@ -591,7 +589,7 @@ figure.image-display
<a id="ngForm"></a>
.l-sub-section
:marked
### The NgForm directive
### The _NgForm_ directive
What `NgForm` directive? We didn't add an [NgForm](../api/forms/index/NgForm-directive.html) directive!
Angular did. Angular creates and attaches an `NgForm` directive to the `<form>` tag automatically.
@ -629,7 +627,7 @@ figure.image-display
jazzing it up won't teach us anything new about forms.
But this is an opportunity to exercise some of our newly won
binding skills.
If you're not interested, you can skip to the chapter's conclusion
If you're not interested, you can skip to the guide's conclusion
and not miss a thing.
:marked
Let's do something more strikingly visual.
@ -670,7 +668,7 @@ figure.image-display
:marked
## Conclusion
The Angular form techniques discussed in this chapter take
The Angular form techniques discussed in this guide take
advantage of the following framework features to provide support for data modification, validation and more:
- An Angular HTML form template.