X Tutup
Skip to content

Commit a29c2cf

Browse files
committed
doc(form): updated to reflect the latest changes
1 parent afe617a commit a29c2cf

File tree

1 file changed

+72
-82
lines changed

1 file changed

+72
-82
lines changed

docs/content/guide/dev_guide.forms.ngdoc

Lines changed: 72 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,19 @@
22
@name Developer Guide: Forms
33
@description
44

5-
Forms and form controls (`input`, `select`, `textarea`) are user's gateway to your application -
6-
that's how your application accepts input from the user.
5+
Controls (`input`, `select`, `textarea`) are a way for user to enter data.
6+
Form is a collection of controls for the purpose of grouping related controls together.
77

8-
In order to provide good user experience while gathering user input, it is important to validate
9-
this input and give the user hints on how to correct errors. Angular provides several mechanisms
10-
that make this easier, but keep in mind that while client-side validation plays an important role in
11-
providing good user experience, it can be easily circumvented and thus a server-side validation is
12-
still necessary.
8+
Form and controls provide validation services, so that the user can be notified of invalid input.
9+
This provides a better user experience, because the user gets instant feedback on how to correct the error.
10+
Keep in mind that while client-side validation plays an important role in providing good user experience, it can easily be circumvented and thus can not be trusted.
11+
Server-side validation is still necessary for a secure application.
1312

1413

1514
# Simple form
16-
The most important directive is {@link api/angular.module.ng.$compileProvider.directive.ng:model ng-model},
17-
which tells Angular to do two-way data binding. That means, the value in the form control is
18-
synchronized in both directions with the bound model (specified as value of `ng-model` attribute).
19-
15+
The key directive in understanding two-way data-binding is {@link api/angular.module.ng.$compileProvider.directive.ng-model ng-model}.
16+
The `ng-model` provides the two-way data-binding by synchronizing the model to the view, as well as view to the model.
17+
In addition it provides {@link api/angular.module.ng.$compileProvider.directive.ng-model.NgModelController API} for other directives to augment its behavior.
2018

2119
<doc:example>
2220
<doc:source>
@@ -29,8 +27,6 @@ synchronized in both directions with the bound model (specified as value of `ng-
2927
<button ng-click="reset()">RESET</button>
3028
<button ng-click="update(user)">SAVE</button>
3129
</form>
32-
<!-- reading these values outside <form> scope is possible only because we defined these objects
33-
on the parent scope, and ng-model only change properties of this object -->
3430
<pre>form = {{user | json}}</pre>
3531
<pre>master = {{master | json}}</pre>
3632
</div>
@@ -54,47 +50,33 @@ synchronized in both directions with the bound model (specified as value of `ng-
5450
</doc:example>
5551

5652

57-
Note, that the `user.name` is updated immediately - that's because of
58-
{@link api/angular.module.ng.$compileProvide.directive.ng:model-instant ng-model-instant}.
59-
60-
Note, that we use `novalidate` to disable browser's native form validation.
61-
53+
Note that:
6254

63-
## Scoping issues
55+
* the {@link api/angular.module.ng.$compileProvider.directive.ng-model-instant ng-model-instant} causes the `user.name` to be updated immediately.
6456

65-
Angular sets the model value onto current scope. However it can be confusing where are the scope
66-
borders - in other words, which directives create new scope.
67-
It's crucial to understand how prototypical inheritance works as well as
68-
{@link dev_guide.scopes.internals Angular's scopes}.
69-
70-
In this example, there are actually two directives, that create new scope (`ng-controller` and `form`).
71-
Angular sets the value onto the current scope, so the first input sets value to `scope.user.name`,
72-
where `scope` is the scope on `form` element. Therefore you would not be able to read the value
73-
outside the `form`, because that's a parent scope. That's why we defined the `$scope.user` object
74-
on the parent scope (on `div` element), because `ng-model` access this object through prototypical
75-
inheritance and bind to this object (defined on the parent scope) and we can access it even on
76-
parent scope.
57+
* `novalidate` is used to disable browser's native form validation.
7758

7859

7960

8061
# Using CSS classes
81-
Angular puts some basic css classes onto the form element as well as individual form control
82-
elements, to allow you to style them differently, depending on their state. These css classes are:
62+
63+
To allow styling of form as well as controls, `ng-model` add these CSS classes:
8364

8465
- `ng-valid`
8566
- `ng-invalid`
8667
- `ng-pristine`
8768
- `ng-dirty`
8869

89-
Here is the same example with some very basic css, displaying validity of each form control.
90-
Both `user.name` and `user.email` are required, but we display the red background only when they
91-
are dirty, which means the user has already interacted with them.
70+
Following example uses the CSS to display validity of each form control.
71+
In the example both `user.name` and `user.email` are required, but are rendered with red background only when they are dirty.
72+
This ensures that the user is not distracted with an error until after interacting with the control, and failing to satisfy its validity.
9273

9374
<doc:example>
9475
<doc:source>
9576
<div ng-controller="Controller">
9677
<form novalidate class="css-form">
97-
Name: <input type="text" ng-model="user.name" ng-model-instant required /><br />
78+
Name:
79+
<input type="text" ng-model="user.name" ng-model-instant required /><br />
9880
E-mail: <input type="email" ng-model="user.email" required /><br />
9981
Gender: <input type="radio" ng-model="user.gender" value="male" />male
10082
<input type="radio" ng-model="user.gender" value="female" />female<br />
@@ -133,24 +115,15 @@ are dirty, which means the user has already interacted with them.
133115

134116

135117

136-
# Binding to form / form control state
118+
# Binding to form and control state
137119

138-
Each form has an object, that keeps the state of the whole form. This object is an instance of
139-
{@link api/angular.module.ng.$compileProvide.directive.form.FormController FormController}.
140-
In a similar way, each form control with `ng-model` directive has an object, that keeps the state of
141-
the form control. This object is an instance of
142-
{@link api/angular.module.ng.$compileProvide.directive.form.NgModelController NgModelController}.
120+
A form is in instance of {@link api/angular.module.ng.$compileProvider.directive.form.FormController FormController}.
121+
The form instance can optionally be published into the scope using the `name` attribute.
122+
Similarly control is an instance of {@link api/angular.module.ng.$compileProvider.directive.ng-model.NgModelController NgModelController}.
123+
The control instance can similarly be published into the form instance using the `name` attribute.
124+
This implies that the internal state of both the form and the control is available for binding in the view using the standard binding primitives.
143125

144-
The css classes used in the previous example are nothing else than just a reflection of these objects.
145-
But using css classes is not flexible enough - we need to do more. So this example shows, how to
146-
access these state objects and how to bind to them.
147-
148-
Note, we added `name` attribute to the form element as well as to the form controls, so that we have access
149-
these objects. When a form has `name` attribute, its `FormController` is published onto the scope.
150-
In a similar way, if a form control has `name` attribute, a reference to its `NgModelController` is
151-
stored on the `FormController`.
152-
153-
**Some changes to notice:**
126+
This allows us to extend the above example with these features:
154127

155128
- RESET button is enabled only if form has some changes
156129
- SAVE button is enabled only if form has some changes and is valid
@@ -160,22 +133,26 @@ stored on the `FormController`.
160133
<doc:source>
161134
<div ng-controller="Controller">
162135
<form name="form" class="css-form" novalidate>
163-
Name: <input type="text" ng-model="user.name" name="userName" required /><br />
164-
E-mail: <input type="email" ng-model="user.email" name="userEmail" required/><br />
165-
<span ng-show="form.userEmail.$dirty && form.userEmail.$invalid">Invalid:
166-
<span ng-show="form.userEmail.$error.REQUIRED">Please tell us your email.</span>
167-
<span ng-show="form.userEmail.$error.EMAIL">This is not a valid email.</span><br />
168-
</span>
136+
Name:
137+
<input type="text" ng-model="user.name" name="uName" required /><br />
138+
E-mail:
139+
<input type="email" ng-model="user.email" name="uEmail" required/><br />
140+
<div ng-show="form.uEmail.$dirty && form.uEmail.$invalid">Invalid:
141+
<span ng-show="form.uEmail.$error.REQUIRED">Tell us your email.</span>
142+
<span ng-show="form.uEmail.$error.EMAIL">This is not a valid email.</span>
143+
</div>
169144

170145
Gender: <input type="radio" ng-model="user.gender" value="male" />male
171146
<input type="radio" ng-model="user.gender" value="female" />female<br />
172147

173-
<input type="checkbox" ng-model="user.agree" name="userAgree" required />I agree:
174-
<input ng-show="user.agree" type="text" ng-model="user.agreeSign" ng-model-instant required /><br />
148+
<input type="checkbox" ng-model="user.agree" name="userAgree" required />
149+
I agree: <input ng-show="user.agree" type="text" ng-model="user.agreeSign"
150+
ng-model-instant required /><br />
175151
<div ng-show="!user.agree || !user.agreeSign">Please agree and sign.</div>
176152

177153
<button ng-click="reset()" disabled="{{isUnchanged(user)}}">RESET</button>
178-
<button ng-click="update(user)" disabled="{{form.$invalid || isUnchanged(user)}}">SAVE</button>
154+
<button ng-click="update(user)"
155+
disabled="{{form.$invalid || isUnchanged(user)}}">SAVE</button>
179156
</form>
180157
</div>
181158

@@ -203,39 +180,51 @@ stored on the `FormController`.
203180

204181

205182

206-
# Advanced / custom validation
183+
# Custom Validation
207184

208185
Angular provides basic implementation for most common html5 {@link api/angular.module.ng.$compileProvider.directive.input input}
209-
types ({@link api/angular.module.ng.$compileProvider.directive.input.text text}, {@link api/angular.module.ng.$compileProvider.directive.input.number number}, {@link api/angular.module.ng.$compileProvider.directive.input.url url}, {@link api/angular.module.ng.$compileProvider.directive.input.email email}, {@link api/angular.module.ng.$compileProvider.directive.input.radio radio}, {@link api/angular.module.ng.$compileProvider.directive.input.checkbox checkbox}), as well as some directives for validation (`required`, `pattern`, `minlength`, `maxlength`, `min`, `max`).
186+
types: ({@link api/angular.module.ng.$compileProvider.directive.input.text text}, {@link api/angular.module.ng.$compileProvider.directive.input.number number}, {@link api/angular.module.ng.$compileProvider.directive.input.url url}, {@link api/angular.module.ng.$compileProvider.directive.input.email email}, {@link api/angular.module.ng.$compileProvider.directive.input.radio radio}, {@link api/angular.module.ng.$compileProvider.directive.input.checkbox checkbox}), as well as some directives for validation (`required`, `pattern`, `minlength`, `maxlength`, `min`, `max`).
187+
188+
Defining your own validator can be done by defining your own directive which adds a custom validation function to the `ng-model` {@link api/angular.module.ng.$compileProvider.directive.ng-model.NgModelController controller}.
189+
To get a hold of the controller the directive specifies a dependency as shown in the example below.
190+
The validation can occur in two places:
210191

211-
However, when this is not enough for your application, you can simply define a custom directive.
212-
This directive can require `ngModel`, which means it can't exist without `ng-model` and its linking
213-
function gets fourth argument - an instance of `NgModelController`, which is a communication channel
214-
to `ng-model`, that allows you to hook into the validation process.
192+
* **Model to View update** -
193+
Whenever the bound model changes, all functions in {@link api/angular.module.ng.$compileProvider.directive.ng-model.NgModelController#$formatters NgModelController#$formatters} array are pipe-lined, so that each of these functions has an opportunity to format the value and change validity state of the form control through {@link api/angular.module.ng.$compileProvider.directive.ng-model.NgModelController#$setValidity NgModelController#$setValidity}.
215194

216-
## Model to View update
217-
Whenever the bound model changes, all functions in {@link api/angular.module.ng.$compileProvider.directive.ng:model.NgModelController#formatters NgModelController#formatters} array are pipe-lined, so that each of these functions has an opportunity to format the value and change validity state of the form control through {@link api/angualar.module.ng.$compileProvider.directive.ng:model.NgModelController#$setValidity NgModelController#$setValidity}.
195+
* **View to Model update** -
196+
In a similar way, whenever a user interacts with a control, the controll calls {@link api/angular.module.ng.$compileProvider.directive.ng-model.NgModelController#$setViewValue NgModelController#$setViewValue}.
197+
This in turn pipelines all functions in {@link api/angular.module.ng.$compileProvider.directive.ng-model.NgModelController#$parsers NgModelController#$parsers} array, so that each of these functions has an opportunity to convert the value and change validity state of the form control through {@link api/angular.module.ng.$compileProvider.directive.ng-model.NgModelController#$setValidity NgModelController#$setValidity}.
218198

219-
## View to Model update
220-
In a similar way, whenever a form control calls {@link api/angular.module.ng.$compileProvider.directive.ng:model.NgModelController#setViewValue NgModelController#setViewValue}, all functions in {@link api/angular.module.ng.$compileProvider.directive.ng:model.NgModelController#parsers NgModelController#parsers} array are pipe-lined, so that each of these functions has an opportunity to correct/convert the value and change validity state of the form control through {@link api/angualar.module.ng.$compileProvider.directive.ng:model.NgModelController#setValidity NgModelController#$setValidity}.
199+
In the following example we create two directives.
221200

222-
In this example we create two simple directives. The first one is `integer` and it validates whether the input is valid integer, so for example `1.23` is an invalid value. Note, that we unshift the array instead of pushing - that's because we want to get a string value, so we need to execute the validation function before a conversion to number happens.
201+
* The first one is `integer` and it validates whether the input is a valid integer.
202+
For example `1.23` is an invalid value, since it contains a fraction.
203+
Note, that we unshift the array instead of pushing.
204+
This is because we want to be first parser and consume the control string value, as we need to execute the validation function before a conversion to number occurs.
223205

224-
The second directive is `smart-float`. It parses both `1.2` and `1,2` into a valid float number `1.2`. Note, we can't use input type `number` here - browser would not allow user to type invalid number such as `1,2`.
206+
* The second directive is a `smart-float`.
207+
It parses both `1.2` and `1,2` into a valid float number `1.2`.
208+
Note that, we can't use input type `number` here as HTML5 browsers would not allow the user to type what it would consider an invalid number such as `1,2`.
225209

226210

227211
<doc:example module="form-example1">
228212
<doc:source>
229213
<div ng-controller="Controller">
230214
<form name="form" class="css-form" novalidate>
231215
<div>
232-
Size (integer 0 - 10): <input type="number" ng-model="size" name="size" min="0" max="10" integer />{{size}}<br />
216+
Size (integer 0 - 10):
217+
<input type="number" ng-model="size" name="size"
218+
min="0" max="10" integer />{{size}}<br />
233219
<span ng-show="form.size.$error.INTEGER">This is not valid integer!</span>
234-
<span ng-show="form.size.$error.MIN || form.size.$error.MAX">The value must be in range 0 to 10!</span>
220+
<span ng-show="form.size.$error.MIN || form.size.$error.MAX">
221+
The value must be in range 0 to 10!</span>
235222
</div>
236223

237224
<div>
238-
Length (float): <input type="text" ng-model="length" name="length" smart-float />{{length}}<br />
225+
Length (float):
226+
<input type="text" ng-model="length" name="length" smart-float />
227+
{{length}}<br />
239228
<span ng-show="form.length.$error.FLOAT">This is not valid number!</span>
240229
</div>
241230
</form>
@@ -287,16 +276,17 @@ The second directive is `smart-float`. It parses both `1.2` and `1,2` into a val
287276

288277

289278
# Implementing custom form control (using ng-model)
290-
Angular has all the basic form controls implemented ({@link api/angular.module.ng.$compileProvider.directive.input input}, {@link api/angular.module.ng.$compileProvider.directive.select select}, {@link api/angular.module.ng.$compileProvider.directive.textarea textarea}), so most of the time you should be just fine with them. However, if you need more flexibility, you can write your own form control - it's gonna be a directive again.
279+
Angular implements all of the basic HTML form controls ({@link api/angular.module.ng.$compileProvider.directive.input input}, {@link api/angular.module.ng.$compileProvider.directive.select select}, {@link api/angular.module.ng.$compileProvider.directive.textarea textarea}), which should be sufficient for most cases.
280+
However, if you need more flexibility, you can write your own form control as a directive.
291281

292-
You basically need to do two things to get it working together with `ng-model` binding:
282+
In order for custom control to work with `ng-model` and to achieve two-way data-binding it needs to:
293283

294-
- implement `render` method, that knows how to reflect value change to view,
295-
- call `setViewValue` method, whenever the view value changes - that's usually inside DOM Event listener.
284+
- implement `render` method, which is responsible for rendering the data after it passed the {@link api/angular.module.ng.$compileProvider.directive.ng-model.NgModelController#$formatters NgModelController#$formatters},
285+
- call `$setViewValue` method, whenever the user interacts with the control and model needs to be updated. This is usually done inside a DOM Event listener.
296286

297287
See {@link api/angular.module.ng.$compileProvider.directive $compileProvider.directive} for more info.
298288

299-
This example shows how easy it is to add a support for binding contentEditable elements.
289+
The following example shows how to add two-way data-binding to contentEditable elements.
300290

301291
<doc:example module="form-example2">
302292
<doc:source>

0 commit comments

Comments
 (0)
X Tutup