docs(forms): add link to Dart sample (#2176)
Contributes to #1598. Also: - Trimmed trailing whitespace. - Fixing user-input (since we don’t need the “Run the” in the link).
This commit is contained in:
parent
9b3614d151
commit
fcaf8fa365
|
@ -1,6 +1,5 @@
|
|||
include ../_util-fns
|
||||
|
||||
<!-- http://plnkr.co/edit/wg154K -->
|
||||
: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.
|
||||
|
@ -30,6 +29,8 @@ include ../_util-fns
|
|||
|
||||
- How to share information across controls with template reference variables
|
||||
|
||||
Run the <live-example></live-example>.
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Template-driven forms
|
||||
|
|
|
@ -6,7 +6,7 @@ include ../_util-fns
|
|||
In this chapter we learn to bind to those events using the Angular
|
||||
event binding syntax.
|
||||
|
||||
<live-example>Run the live example</live-example>.
|
||||
Run the <live-example></live-example>.
|
||||
|
||||
:marked
|
||||
## Binding to user input events
|
||||
|
|
|
@ -21,15 +21,15 @@ include ../_util-fns
|
|||
|
||||
- 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
|
||||
- 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
|
||||
|
||||
<live-example>Live Example</live-example>
|
||||
|
||||
Run the <live-example></live-example>.
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
|
@ -107,13 +107,13 @@ include ../_quickstart_repo
|
|||
|
||||
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?`.
|
||||
|
||||
We can create a new hero like this:
|
||||
code-example(format="").
|
||||
let myHero = new Hero(42, 'SkyDog',
|
||||
'Fetch any object at any distance',
|
||||
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
|
||||
|
@ -159,7 +159,7 @@ code-example(format="").
|
|||
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 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`.
|
||||
|
||||
|
@ -191,7 +191,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_ 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
|
||||
|
@ -230,7 +230,7 @@ code-example(format="").
|
|||
|
||||
**We are not using Angular yet**. There are no bindings. No extra directives. Just layout.
|
||||
|
||||
The `container`, `form-group`, `form-control`, and `btn` classes
|
||||
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!
|
||||
|
@ -300,7 +300,7 @@ figure.image-display
|
|||
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)]="..."`.
|
||||
|
||||
|
@ -314,13 +314,13 @@ figure.image-display
|
|||
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!**
|
||||
|
||||
Notice that we also added a `name` attribute to our `<input>` tag and set it to "name"
|
||||
Notice that we also added a `name` attribute to our `<input>` tag and set it to "name"
|
||||
which makes sense for the hero's name. Any unique value will do, but using a descriptive name is helpful.
|
||||
Defining a `name` attribute is a requirement when using `[(ngModel)]` in combination with a form.
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
Internally Angular creates `FormControls` and registers them with an `NgForm` directive that Angular
|
||||
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).
|
||||
|
||||
|
@ -340,7 +340,7 @@ figure.image-display
|
|||
- Each input element has an `id` property that is used by the `label` element's `for` attribute
|
||||
to match the label to it's input control.
|
||||
- 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:
|
||||
figure.image-display
|
||||
|
@ -355,7 +355,7 @@ figure.image-display
|
|||
:marked
|
||||
### 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.
|
||||
|
||||
In a Property Binding, a value flows from the model to a target property on screen.
|
||||
|
@ -405,7 +405,7 @@ figure.image-display
|
|||
The *NgModel* directive doesn't just track state; it updates the control with special Angular CSS classes that reflect the state.
|
||||
We can leverage those class names to change the appearance of the
|
||||
control and make messages appear or disappear.
|
||||
|
||||
|
||||
table
|
||||
tr
|
||||
th State
|
||||
|
@ -491,32 +491,32 @@ figure.image-display
|
|||
1. the "*is required*" message in a nearby `<div>` which we'll display only if the control is invalid.
|
||||
|
||||
Here's how we do it for the *name* input box:
|
||||
+makeExample('forms/ts/app/hero-form.component.html',
|
||||
'name-with-error-msg',
|
||||
+makeExample('forms/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 "ngModel".
|
||||
.l-sub-section
|
||||
:marked
|
||||
Why "ngModel"?
|
||||
Why "ngModel"?
|
||||
A directive's [exportAs](../api/core/index/DirectiveMetadata-class.html#!#exportAs-anchor) property
|
||||
tells Angular how to link the reference variable to the directive.
|
||||
We set `name` to `ngModel` because the `ngModel` directive's `exportAs` property happens to be "ngModel".
|
||||
|
||||
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',
|
||||
+makeExample('forms/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.
|
||||
|
||||
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,
|
||||
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.
|
||||
|
@ -527,30 +527,30 @@ figure.image-display
|
|||
We can add the same kind of error handling to the `<select>` if we want
|
||||
but it's not imperative because the selection box already constrains the
|
||||
power to valid value.
|
||||
|
||||
|
||||
<a id="new-hero"></a>
|
||||
<a id="reset"></a>
|
||||
<a id="reset"></a>
|
||||
.l-main-section
|
||||
:marked
|
||||
## Add a hero and reset the form
|
||||
We'd like to add a new hero in this 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.
|
||||
+makeExample('forms/ts/app/hero-form.component.html',
|
||||
'new-hero-button',
|
||||
+makeExample('forms/ts/app/hero-form.component.html',
|
||||
'new-hero-button',
|
||||
'app/hero-form.component.html (New Hero button)')
|
||||
:marked
|
||||
+makeExample('forms/ts/app/hero-form.component.ts',
|
||||
'new-hero-v1',
|
||||
+makeExample('forms/ts/app/hero-form.component.ts',
|
||||
'new-hero-v1',
|
||||
'app/hero-form.component.ts (New Hero method - v1)')(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.
|
||||
That's understandable as these are required fields.
|
||||
That's understandable as these are required fields.
|
||||
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.
|
||||
|
||||
|
||||
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
|
||||
|
@ -559,26 +559,26 @@ figure.image-display
|
|||
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 manually with a small trick.
|
||||
We'll have to reset the form controls manually with a small trick.
|
||||
We add an `active` flag to the component, initialized to `true`. When we add a new hero,
|
||||
we toggle `active` false and then immediately back to true with a quick `setTimeout`.
|
||||
+makeExample('forms/ts/app/hero-form.component.ts',
|
||||
'new-hero',
|
||||
+makeExample('forms/ts/app/hero-form.component.ts',
|
||||
'new-hero',
|
||||
'app/hero-form.component.ts (New Hero method - final)')(format=".")
|
||||
:marked
|
||||
Then we bind the form element to this `active` flag.
|
||||
+makeExample('forms/ts/app/hero-form.component.html',
|
||||
'form-active',
|
||||
+makeExample('forms/ts/app/hero-form.component.html',
|
||||
'form-active',
|
||||
'app/hero-form.component.html (Form tag)')
|
||||
:marked
|
||||
With `NgIf` bound to the `active` flag,
|
||||
With `NgIf` bound to the `active` flag,
|
||||
clicking "New Hero" removes the form from the DOM and recreates it in a blink of an eye.
|
||||
The re-created form is in a pristine state. The error message is hidden.
|
||||
.l-sub-section
|
||||
:marked
|
||||
This is a temporary workaround while we await a proper form reset feature.
|
||||
:marked
|
||||
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Submit the form with **ngSubmit**
|
||||
|
@ -602,7 +602,7 @@ figure.image-display
|
|||
:marked
|
||||
### The NgForm directive
|
||||
What `NgForm` directive? We didn't add an [NgForm](../api/common/index/NgForm-directive.html) directive!
|
||||
|
||||
|
||||
Angular did. Angular creates and attaches an `NgForm` directive to the `<form>` tag automatically.
|
||||
|
||||
The `NgForm` directive supplements the `form` element with additional features.
|
||||
|
@ -610,7 +610,7 @@ figure.image-display
|
|||
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
|
||||
Later in the template we bind the button's `disabled` property to the form's over-all validity via
|
||||
the `heroForm` variable. Here's that bit of markup:
|
||||
|
@ -686,7 +686,7 @@ figure.image-display
|
|||
- A form component class with a `Component` decorator.
|
||||
- The `ngSubmit` directive for handling the form submission.
|
||||
- Template reference variables such as `#heroForm`, `#name` and `#power`.
|
||||
- The `[(ngModel)]` syntax and a `name` attribute for two-way data binding, validation and change tracking.
|
||||
- The `[(ngModel)]` syntax and a `name` attribute for two-way data binding, validation and change tracking.
|
||||
- The reference variable’s `valid` property on input controls to check if a control is valid and show/hide error messages.
|
||||
- Controlling the submit button's enabled state by binding to `NgForm` validity.
|
||||
- Custom CSS classes that provide visual feedback to users about invalid controls.
|
||||
|
@ -704,7 +704,7 @@ figure.image-display
|
|||
.file hero-form.component.ts
|
||||
.file main.ts
|
||||
.file node_modules ...
|
||||
.file typings ...
|
||||
.file typings ...
|
||||
.file index.html
|
||||
.file package.json
|
||||
.file tsconfig.json
|
||||
|
@ -718,12 +718,12 @@ figure.image-display
|
|||
forms/ts/app/hero.ts,
|
||||
forms/ts/app/app.module.ts,
|
||||
forms/ts/app/app.component.ts,
|
||||
forms/ts/app/main.ts,
|
||||
forms/ts/app/main.ts,
|
||||
forms/ts/index.html,
|
||||
forms/ts/forms.css`,
|
||||
'final, final,,,,,',
|
||||
`hero-form.component.ts,
|
||||
hero-form.component.html,
|
||||
hero-form.component.html,
|
||||
hero.ts,
|
||||
app.module.ts,
|
||||
app.component.ts,
|
||||
|
|
|
@ -6,7 +6,7 @@ include ../_util-fns
|
|||
In this chapter we learn to bind to those events using the Angular
|
||||
event binding syntax.
|
||||
|
||||
<live-example>Run the live example</live-example>.
|
||||
Run the <live-example></live-example>.
|
||||
|
||||
:marked
|
||||
## Binding to user input events
|
||||
|
|
Loading…
Reference in New Issue