parent
92f1690b73
commit
8e8963270b
|
@ -4,16 +4,16 @@
|
|||
<!-- #docregion edit-div -->
|
||||
<div [hidden]="submitted">
|
||||
<h1>Hero Form</h1>
|
||||
<!-- #docregion ng-submit -->
|
||||
<form (ng-submit)="onSubmit()" #hf="form">
|
||||
<!-- #enddocregion ng-submit -->
|
||||
<!-- #docregion ngSubmit -->
|
||||
<form (ngSubmit)="onSubmit()" #heroForm="ngForm">
|
||||
<!-- #enddocregion ngSubmit -->
|
||||
<!-- #enddocregion edit-div -->
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<input type="text" class="form-control" required
|
||||
[(ng-model)]="model.name"
|
||||
ng-control="name" #name="form" >
|
||||
[(ngModel)]="model.name"
|
||||
ngControl="name" #name="ngForm" >
|
||||
<div [hidden]="name.valid" class="alert alert-danger">
|
||||
Name is required
|
||||
</div>
|
||||
|
@ -23,22 +23,22 @@
|
|||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" class="form-control"
|
||||
[(ng-model)]="model.alterEgo"
|
||||
ng-control="alterEgo" >
|
||||
[(ngModel)]="model.alterEgo"
|
||||
ngControl="alterEgo" >
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select class="form-control" required
|
||||
[(ng-model)]="model.power"
|
||||
ng-control="power" >
|
||||
<option *ng-for="#p of powers" [value]="p">{{p}}</option>
|
||||
[(ngModel)]="model.power"
|
||||
ngControl="power" >
|
||||
<option *ngFor="#p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- #docregion submit-button -->
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="!hf.form.valid">Submit</button>
|
||||
[disabled]="!heroForm.form.valid">Submit</button>
|
||||
<!-- #enddocregion submit-button -->
|
||||
<!-- #docregion edit-div -->
|
||||
</form>
|
||||
|
|
|
@ -4,26 +4,26 @@
|
|||
<form>
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<!-- #docregion ng-control-1 -->
|
||||
<!-- #docregion ngControl-1 -->
|
||||
<input type="text" class="form-control" required
|
||||
[(ng-model)]="model.name"
|
||||
ng-control="name" >
|
||||
<!-- #enddocregion ng-control-1 -->
|
||||
[(ngModel)]="model.name"
|
||||
ngControl="name" >
|
||||
<!-- #enddocregion ngControl-1 -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" class="form-control"
|
||||
[(ng-model)]="model.alterEgo"
|
||||
ng-control="alterEgo" >
|
||||
[(ngModel)]="model.alterEgo"
|
||||
ngControl="alterEgo" >
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select class="form-control" required
|
||||
[(ng-model)]="model.power"
|
||||
ng-control="power" >
|
||||
<option *ng-for="#p of powers" [value]="p">{{p}}</option>
|
||||
[(ngModel)]="model.power"
|
||||
ngControl="power" >
|
||||
<option *ngFor="#p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -2,28 +2,28 @@
|
|||
<div class="container">
|
||||
<h1>Hero Form</h1>
|
||||
<form>
|
||||
<!-- #docregion ng-model-2 -->
|
||||
<!-- #docregion ngModel-2 -->
|
||||
{{diagnostic}}
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" class="form-control" required
|
||||
[(ng-model)]="model.name" >
|
||||
[(ngModel)]="model.name" >
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" class="form-control"
|
||||
[(ng-model)]="model.alterEgo">
|
||||
[(ngModel)]="model.alterEgo">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select class="form-control" required
|
||||
[(ng-model)]="model.power">
|
||||
<option *ng-for="#p of powers" [value]="p">{{p}}</option>
|
||||
[(ngModel)]="model.power">
|
||||
<option *ngFor="#p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- #enddocregion ng-model-2 -->
|
||||
<!-- #enddocregion ngModel-2 -->
|
||||
|
||||
<button type="submit" class="btn btn-default">Submit</button>
|
||||
</form>
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
<form>
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<!-- #docregion ng-model-1 -->
|
||||
<!-- #docregion ngModel-1 -->
|
||||
<input type="text" class="form-control" required
|
||||
[(ng-model)]="model.name" >
|
||||
[(ngModel)]="model.name" >
|
||||
TODO: remove this: {{model.name}}
|
||||
<!-- #enddocregion ng-model-1 -->
|
||||
<!-- #enddocregion ngModel-1 -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
|
@ -20,7 +20,7 @@
|
|||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select class="form-control" required>
|
||||
<option *ng-for="#p of powers" [value]="p">{{p}}</option>
|
||||
<option *ngFor="#p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- #enddocregion powers -->
|
||||
|
|
|
@ -4,25 +4,25 @@
|
|||
<form>
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<!-- #docregion ng-model-3 -->
|
||||
<!-- #docregion ngModel-3 -->
|
||||
<input type="text" class="form-control" required
|
||||
[ng-model]="model.name"
|
||||
(ng-model-change)="model.name = $event" >
|
||||
[ngModel]="model.name"
|
||||
(ngModel-change)="model.name = $event" >
|
||||
TODO: remove this: {{model.name}}
|
||||
<!-- #enddocregion ng-model-3 -->
|
||||
<!-- #enddocregion ngModel-3 -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" class="form-control"
|
||||
[(ng-model)]="model.alterEgo">
|
||||
[(ngModel)]="model.alterEgo">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select class="form-control" required
|
||||
[(ng-model)]="model.power">
|
||||
<option *ng-for="#p of powers" [value]="p">{{p}}</option>
|
||||
[(ngModel)]="model.power">
|
||||
<option *ngFor="#p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -4,27 +4,27 @@
|
|||
<form>
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<!-- #docregion ng-control-2 -->
|
||||
<!-- #docregion ngControl-2 -->
|
||||
<input type="text" class="form-control" required
|
||||
[(ng-model)]="model.name"
|
||||
ng-control="name" #spy >
|
||||
[(ngModel)]="model.name"
|
||||
ngControl="name" #spy >
|
||||
TODO: remove this: {{spy.className}}
|
||||
<!-- #enddocregion ng-control-2 -->
|
||||
<!-- #enddocregion ngControl-2 -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" class="form-control"
|
||||
[(ng-model)]="model.alterEgo"
|
||||
ng-control="alterEgo" >
|
||||
[(ngModel)]="model.alterEgo"
|
||||
ngControl="alterEgo" >
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select class="form-control" required
|
||||
[(ng-model)]="model.power"
|
||||
ng-control="power" >
|
||||
<option *ng-for="#p of powers" [value]="p">{{p}}</option>
|
||||
[(ngModel)]="model.power"
|
||||
ngControl="power" >
|
||||
<option *ngFor="#p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ name: hero_form
|
|||
description: Form example
|
||||
version: 0.0.1
|
||||
dependencies:
|
||||
angular2: 2.0.0-alpha.47
|
||||
angular2: 2.0.0-alpha.52
|
||||
browser: ^0.10.0
|
||||
transformers:
|
||||
- angular2:
|
||||
|
|
|
@ -20,11 +20,11 @@ include ../../../../_includes/_util-fns
|
|||
|
||||
- How to build an Angular form with a component and template
|
||||
|
||||
- The `ng-model` two-way data binding syntax for reading and writing values to input controls
|
||||
- The `ngModel` two-way data binding syntax for reading and writing values to input controls
|
||||
|
||||
- The `ng-control` directive to track the change state and validity of form controls
|
||||
- The `ngControl` directive to track the change state and validity of form controls
|
||||
|
||||
- The special CSS classes that `ng-control` adds to form controls and how to use them to provide strong visual feedback
|
||||
- The special CSS classes that `ngControl` adds to form controls and how to use them to provide strong visual feedback
|
||||
|
||||
- How to display validation errors to users and enable/disable form controls
|
||||
|
||||
|
@ -79,11 +79,11 @@ figure.image-display
|
|||
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 **ng-model** directive to each form input control.
|
||||
1. Add the **ng-control** directive to each form input control.
|
||||
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 **ng-submit**.
|
||||
1. Handle form submission with **ngSubmit**.
|
||||
1. Change the form's display after submission.
|
||||
|
||||
:marked
|
||||
|
@ -236,7 +236,7 @@ figure.image-display
|
|||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Add powers with ***ng-for**
|
||||
## 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`).
|
||||
|
||||
|
@ -255,7 +255,7 @@ figure.image-display
|
|||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Two-way data binding with ***ng-model**
|
||||
## Two-way data binding with ***ngModel**
|
||||
Running the app right now would be disappointing.
|
||||
|
||||
figure.image-display
|
||||
|
@ -275,7 +275,7 @@ figure.image-display
|
|||
|
||||
Find the `<input>` tag for Name and update it like this:
|
||||
|
||||
+makeExample('forms/dart/lib/hero_form_component_ngmodel_ngfor.html', 'ng-model-1', 'lib/hero_form_component.html (excerpt)')(format=".")
|
||||
+makeExample('forms/dart/lib/hero_form_component_ngmodel_ngfor.html', 'ngModel-1', 'lib/hero_form_component.html (excerpt)')(format=".")
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
|
@ -284,32 +284,32 @@ figure.image-display
|
|||
We left ourselves a note to throw it way when we're done.
|
||||
|
||||
:marked
|
||||
Focus on the binding syntax: `[(ng-model)]="..."`.
|
||||
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="ng-model in action")
|
||||
img(src="/resources/images/devguide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action")
|
||||
:marked
|
||||
The diagnostic is evidence that values really are flowing from the input box to the model and
|
||||
back again. **That's two-way data binding!**
|
||||
|
||||
Let's add similar `[(ng-model)]` bindings to Alter Ego and Hero Power.
|
||||
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 the form should have three `[(ng-model)]` bindings that
|
||||
After revision, the core of the form should have three `[(ngModel)]` bindings that
|
||||
look much like this:
|
||||
|
||||
+makeExample('forms/dart/lib/hero_form_component_ngmodel2.html', 'ng-model-2', 'lib/hero_form_component.html (excerpt)')(format=".")
|
||||
+makeExample('forms/dart/lib/hero_form_component_ngmodel2.html', 'ngModel-2', 'lib/hero_form_component.html (excerpt)')(format=".")
|
||||
|
||||
:marked
|
||||
If we ran the app right now and changed every Hero model property, the form might look like this:
|
||||
figure.image-display
|
||||
img(src="images/ng-model-in-action-2.png" width="500px" alt="ng-model in super action")
|
||||
img(src="images/ng-model-in-action-2.png" width="500px" alt="ngModel in super action")
|
||||
:marked
|
||||
The diagnostic near the top of the form
|
||||
confirms that our changes to the values are reflected in the model.
|
||||
|
@ -318,9 +318,9 @@ figure.image-display
|
|||
|
||||
|
||||
.l-sub-section
|
||||
h3 Inside [(ng-model)]
|
||||
h3 Inside [(ngModel)]
|
||||
:marked
|
||||
*This section is an optional deep dive into [(ng-model)]. Not interested? Skip ahead!*
|
||||
*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.
|
||||
|
||||
|
@ -337,22 +337,22 @@ figure.image-display
|
|||
|
||||
In fact, we can break the `NgModel` binding into its two separate modes
|
||||
as in this rewrite of the Name `<input>` binding:
|
||||
+makeExample('forms/dart/lib/hero_form_component_ngmodelchange.html', 'ng-model-3')(format=".")
|
||||
+makeExample('forms/dart/lib/hero_form_component_ngmodelchange.html', 'ngModel-3')(format=".")
|
||||
|
||||
:marked
|
||||
<br>The property binding should feel familiar. The event binding might seem strange.
|
||||
|
||||
The name `ng-model-change` specifies an event property of the `NgModel` directive.
|
||||
The name `ngModel-change` specifies an event property of the `NgModel` directive.
|
||||
When Angular sees a binding target in the form <span style="font-family:courier">[(abc)]</span>,
|
||||
it expects the `abc` directive to have an `abc` input property and an `abc-change` 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 `ng-model-change` property doesn't produce a DOM event; it's an Angular `EventEmitter`
|
||||
The `ngModel-change` 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? `[(ng-model)]` is usually what we want, but
|
||||
Nice to know but is it practical? `[(ngModel)]` is usually what we want, but
|
||||
we might split the binding when the event handling has to do something special
|
||||
such as debounce or throttle the keystrokes.
|
||||
|
||||
|
@ -364,7 +364,7 @@ figure.image-display
|
|||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Track change-state and validity with **ng-control**
|
||||
## 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.
|
||||
|
@ -384,15 +384,15 @@ figure.image-display
|
|||
control and make messages appear or disappear.
|
||||
|
||||
We'll explore those effects soon. Right now
|
||||
let's **add `ng-control`to all three form controls**,
|
||||
let's **add `ngControl`to all three form controls**,
|
||||
starting with the Name input box.
|
||||
+makeExample('forms/dart/lib/hero_form_component_ngcontrol.html', 'ng-control-1', 'lib/hero_form_component.html (excerpt)')(format=".")
|
||||
+makeExample('forms/dart/lib/hero_form_component_ngcontrol.html', 'ngControl-1', 'lib/hero_form_component.html (excerpt)')(format=".")
|
||||
:marked
|
||||
Be sure to assign a unique name to each `ng-control` directive.
|
||||
Be sure to assign a unique name to each `ngControl` directive.
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
Angular registers controls under their `ng-control` names
|
||||
Angular registers controls under their `ngControl` names
|
||||
with the `NgForm` directive.
|
||||
We didn't add the `NgForm` directive explicitly but it's here;
|
||||
we'll talk about it [later in this chapter](#ng-form).
|
||||
|
@ -429,7 +429,7 @@ figure.image-display
|
|||
named **spy**
|
||||
to the Name `<input>` tag and use the spy to display those classes.
|
||||
|
||||
+makeExample('forms/dart/lib/hero_form_component_spy.html', 'ng-control-2')(format=".")
|
||||
+makeExample('forms/dart/lib/hero_form_component_spy.html', 'ngControl-2')(format=".")
|
||||
|
||||
:marked
|
||||
Now run the app, and look at the Name input box.
|
||||
|
@ -442,8 +442,8 @@ figure.image-display
|
|||
|
||||
The classes are displayed as follows:
|
||||
|
||||
1. `form-control ng-untouched ng-pristine ng-valid` (initial state)
|
||||
1. `form-control ng-pristine ng-valid ng-touched` (after clicking)
|
||||
1. `form-control ng-untouched ng-valid ng-pristine` (initial state)
|
||||
1. `form-control ng-valid ng-pristine ng-touched` (after clicking)
|
||||
1. `form-control ng-valid ng-touched ng-dirty` (after changing)
|
||||
1. `form-control ng-touched ng-dirty ng-invalid` (after erasing)
|
||||
|
||||
|
@ -498,11 +498,11 @@ figure.image-display
|
|||
+makeExample('forms/dart/lib/hero_form_component.html', 'name-with-error-msg', 'lib/hero_form_component.html (excerpt)', stylePattern)(format=".")
|
||||
|
||||
:marked
|
||||
We initialized the template local variable with the string "form"
|
||||
(`#name="form"`).
|
||||
We initialized the template local variable with the string "ngForm"
|
||||
(`#name="ngForm"`).
|
||||
|
||||
Angular recognizes that syntax and sets the `name` variable
|
||||
to the `Control` object identified by the `ng-control` directive that,
|
||||
to the `Control` object identified by the `ngControl` directive that,
|
||||
not coincidentally, we called "name".
|
||||
|
||||
We bind the `Control` object's `valid` property to the element's `hidden` property.
|
||||
|
@ -513,14 +513,14 @@ figure.image-display
|
|||
h3 The NgForm directive
|
||||
|
||||
:marked
|
||||
Recall from the previous section that `ng-control` registered this input box with the
|
||||
Recall from the previous section that `ngControl` registered this input box with the
|
||||
`NgForm` directive as "name".
|
||||
|
||||
We didn't add the `NgForm`<!-- TODO: link to (../api/core/NgForm-class.html) --> directive explicitly.
|
||||
Angular added it surreptitiously, wrapping it around the `<form>` element.
|
||||
|
||||
The `NgForm` directive supplements the `<form>` element with additional features.
|
||||
It collects controls (elements identified by an `ng-control` directive)
|
||||
It collects controls (elements identified by an `ngControl` directive)
|
||||
and monitors their properties including their validity.
|
||||
It has its own `valid` property, which is true only if every contained
|
||||
control is valid.
|
||||
|
@ -539,7 +539,7 @@ figure.image-display
|
|||
|
||||
.l-main-section
|
||||
:marked
|
||||
## Submit the form with **ng-submit**
|
||||
## 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
|
||||
|
@ -548,18 +548,18 @@ figure.image-display
|
|||
A "form submit" is meaningless at the moment. To make it meaningful,
|
||||
we'll update the `<form>` tag with another Angular directive, `NgSubmit`,
|
||||
and bind it to the `HeroFormComponent.onSubmit()` method:
|
||||
+makeExample('forms/dart/lib/hero_form_component.html', 'ng-submit')(format=".")
|
||||
+makeExample('forms/dart/lib/hero_form_component.html', 'ngSubmit')(format=".")
|
||||
|
||||
:marked
|
||||
We slipped in something extra there at the end! We defined a
|
||||
template local variable, **`#hf`**, and initialized it with the value "form".
|
||||
template local variable, **`#heroForm`**, and initialized it with the value "ngForm".
|
||||
|
||||
The variable `hf` is now a handle to the `NgForm` as we [discussed earlier](#ng-form)
|
||||
with respect to `ng-control`, although this time we have a reference to the form
|
||||
The variable `heroForm` is now a handle to the `NgForm` as we [discussed earlier](#ng-form)
|
||||
with respect to `ngControl`, although this time we have a reference to the form
|
||||
rather than a control.
|
||||
|
||||
We'll bind the form's overall validity via
|
||||
the `hf` variable to the button's `disabled` property
|
||||
the `heroForm` variable to the button's `disabled` property
|
||||
using an event binding. Here's the code:
|
||||
+makeExample('forms/dart/lib/hero_form_component.html', 'submit-button')(format=".")
|
||||
:marked
|
||||
|
@ -631,10 +631,10 @@ figure.image-display
|
|||
|
||||
- An Angular HTML form template.
|
||||
- A form component class with a `Component` decorator.
|
||||
- The `ng-submit` directive for handling the form submission.
|
||||
- Template local variables such as `#hf`, `#name`, `#alter-ego`, and `#power`.
|
||||
- The `ng-model` directive for two-way data binding.
|
||||
- The `ng-control` directive for validation and form element change tracking.
|
||||
- The `ngSubmit` directive for handling the form submission.
|
||||
- Template local variables such as `#heroForm`, `#name`, `#p`, and `#spy`.
|
||||
- The `ngModel` directive for two-way data binding.
|
||||
- The `ngControl` directive for validation and form element change tracking.
|
||||
- The local variable’s `valid` property on input controls to check if a control is valid and show/hide error messages.
|
||||
- Property binding to disable the submit button when the form is invalid.
|
||||
- Custom CSS classes that provide visual feedback to users about required invalid controls.
|
||||
|
|
Loading…
Reference in New Issue