From 317adb36a480c60f41b6f69bc67d66fe1b08bdae Mon Sep 17 00:00:00 2001
From: Vojta Jina
Date: Mon, 12 Mar 2012 01:25:05 -0700
Subject: docs(guide.forms): Update forms guide
---
docs/content/guide/dev_guide.forms.ngdoc | 836 +++++++++++--------------------
docs/src/templates/docs.css | 4 -
2 files changed, 290 insertions(+), 550 deletions(-)
diff --git a/docs/content/guide/dev_guide.forms.ngdoc b/docs/content/guide/dev_guide.forms.ngdoc
index cbb73abc..c79b9683 100644
--- a/docs/content/guide/dev_guide.forms.ngdoc
+++ b/docs/content/guide/dev_guide.forms.ngdoc
@@ -2,592 +2,336 @@
@name Developer Guide: Forms
@description
-# Overview
+Forms and form controls (`input`, `select`, `textarea`) are user's gateway to your application -
+that's how your application accepts input from the user.
-Forms allow users to enter data into your application. Forms represent the bidirectional data
-bindings in Angular.
+In order to provide good user experience while gathering user input, it is important to validate
+this input and give the user hints on how to correct errors. Angular provides several mechanisms
+that make this easier, but keep in mind that while client-side validation plays an important role in
+providing good user experience, it can be easily circumvented and thus a server-side validation is
+still necessary.
-Forms consist of all of the following:
- - the individual widgets with which users interact
- - the validation rules for widgets
- - the form, a collection of widgets that contains aggregated validation information
+# Simple form
+The most important directive is {@link api/angular.module.ng.$compileProvider.directive.ng:model ng-model},
+which tells Angular to do two-way data binding. That means, the value in the form control is
+synchronized in both directions with the bound model (specified as value of `ng-model` attribute).
-# Form
+
+
+
+
+
+
form = {{user | json}}
+
master = {{master | json}}
+
+
+
+
+
-A form groups a set of widgets together into a single logical data-set. A form is created using
-the {@link api/angular.module.ng.$compileProvider.directive.form <form>} element that calls the
-{@link api/angular.module.ng.$formFactory $formFactory} service. The form is responsible for managing
-the widgets and for tracking validation information.
-A form is:
+Note, that the `user.name` is updated immediately - that's because of
+{@link api/angular.module.ng.$compileProvide.directive.ng:model-instant ng-model-instant}.
-- The collection which contains widgets or other forms.
-- Responsible for marshaling data from the model into a widget. This is
- triggered by {@link api/angular.module.ng.$rootScope.Scope#$watch $watch} of the model expression.
-- Responsible for marshaling data from the widget into the model. This is
- triggered by the widget emitting the `$viewChange` event.
-- Responsible for updating the validation state of the widget, when the widget emits
- `$valid` / `$invalid` event. The validation state is useful for controlling the validation
- errors shown to the user in it consist of:
+Note, that we use `novalidate` to disable browser's native form validation.
- - `$valid` / `$invalid`: Complementary set of booleans which show if a widget is valid / invalid.
- - `$error`: an object which has a property for each validation key emited by the widget.
- The value of the key is always true. If widget is valid, then the `$error`
- object has no properties. For example if the widget emits
- `$invalid` event with `REQUIRED` key. The internal state of the `$error` would be
- updated to `$error.REQUIRED == true`.
-- Responsible for aggregating widget validation information into the form.
+## Scoping issues
- - `$valid` / `$invalid`: Complementary set of booleans which show if all the child widgets
- (or forms) are valid or if any are invalid.
- - `$error`: an object which has a property for each validation key emited by the
- child widget. The value of the key is an array of widgets which fired the invalid
- event. If all child widgets are valid then, then the `$error` object has no
- properties. For example if a child widget emits
- `$invalid` event with `REQUIRED` key. The internal state of the `$error` would be
- updated to `$error.REQUIRED == [ widgetWhichEmitedInvalid ]`.
+Angular sets the model value onto current scope. However it can be confusing where are the scope
+borders - in other words, which directives create new scope.
+It's crucial to understand how prototypical inheritance works as well as
+{@link dev_guide.scopes.internals Angular's scopes}.
+In this example, there are actually two directives, that create new scope (`ng-controller` and `form`).
+Angular sets the value onto the current scope, so the first input sets value to `scope.user.name`,
+where `scope` is the scope on `form` element. Therefore you would not be able to read the value
+outside the `form`, because that's a parent scope. That's why we defined the `$scope.user` object
+on the parent scope (on `div` element), because `ng-model` access this object through prototypical
+inheritance and bind to this object (defined on the parent scope) and we can access it even on
+parent scope.
-# Widgets
-In Angular, a widget is the term used for the UI with which the user input. Examples of
-bult-in Angular widgets are {@link api/angular.module.ng.$compileProvider.directive.input input} and
-{@link api/angular.module.ng.$compileProvider.directive.select select}. Widgets provide the rendering and the user
-interaction logic. Widgets should be declared inside a form, if no form is provided an implicit
-form {@link api/angular.module.ng.$formFactory $formFactory.rootForm} form is used.
-Widgets are implemented as Angular controllers. A widget controller:
+# Using CSS classes
+Angular puts some basic css classes onto the form element as well as individual form control
+elements, to allow you to style them differently, depending on their state. These css classes are:
-- implements methods:
+- `ng-valid`
+- `ng-invalid`
+- `ng-pristine`
+- `ng-dirty`
- - `$render` - Updates the DOM from the internal state as represented by `$viewValue`.
- - `$parseView` - Translate `$viewValue` to `$modelValue`. (`$modelValue` will be assigned to
- the model scope by the form)
- - `$parseModel` - Translate `$modelValue` to `$viewValue`. (`$viewValue` will be assigned to
- the DOM inside the `$render` method)
+Here is the same example with some very basic css, displaying validity of each form control.
+Both `user.name` and `user.email` are required, but we display the red background only when they
+are dirty, which means the user has already interacted with them.
-- responds to events:
+
+
+
+
+
+
+
+
+
+
+
- - `$validate` - Emitted by the form when the form determines that the widget needs to validate
- itself. There may be more then one listener on the `$validate` event. The widget responds
- by emitting `$valid` / `$invalid` event of its own.
-- emits events:
- - `$viewChange` - Emitted when the user interacts with the widget and it is necessary to update
- the model.
- - `$valid` - Emitted when the widget determines that it is valid (usually as a response to
- `$validate` event or inside `$parseView()` or `$parseModel()` method).
- - `$invalid` - Emitted when the widget determines that it is invalid (usually as a response to
- `$validate` event or inside `$parseView()` or `$parseModel()` method).
- - `$destroy` - Emitted when the widget element is removed from the DOM.
+# Binding to form / form control state
+Each form has an object, that keeps the state of the whole form. This object is an instance of
+{@link api/angular.module.ng.$compileProvide.directive.form.FormController FormController}.
+In a similar way, each form control with `ng-model` directive has an object, that keeps the state of
+the form control. This object is an instance of
+{@link api/angular.module.ng.$compileProvide.directive.form.NgModelController NgModelController}.
-# CSS
+The css classes used in the previous example are nothing else than just a reflection of these objects.
+But using css classes is not flexible enough - we need to do more. So this example shows, how to
+access these state objects and how to bind to them.
-Angular-defined widgets and forms set `ng-valid` and `ng-invalid` classes on themselves to allow
-the web-designer a way to style them. If you write your own widgets, then their `$render()`
-methods must set the appropriate CSS classes to allow styling.
-(See {@link dev_guide.templates.css-styling CSS})
+Note, we added `name` attribute to the form element as well as to the form controls, so that we have access
+these objects. When a form has `name` attribute, its `FormController` is published onto the scope.
+In a similar way, if a form control has `name` attribute, a reference to its `NgModelController` is
+stored on the `FormController`.
+**Some changes to notice:**
-# Example
+- RESET button is enabled only if form has some changes
+- SAVE button is enabled only if form has some changes and is valid
+- custom error messages for `user.email` and `user.agree`
-The following example demonstrates:
+
+
+
+
+
+
+
+
+
- - How an error is displayed when a required field is empty.
- - Error highlighting.
- - How form submission is disabled when the form is invalid.
- - The internal state of the widget and form in the the 'Debug View' area.
-
+# Advanced / custom validation
+
+Angular provides basic implementation for most common html5 {@link api/angular.module.ng.$compileProvider.directive.input input}
+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`).
+
+However, when this is not enough for your application, you can simply define a custom directive.
+This directive can require `ngModel`, which means it can't exist without `ng-model` and its linking
+function gets fourth argument - an instance of `NgModelController`, which is a communication channel
+to `ng-model`, that allows you to hook into the validation process.
+
+## Model to View update
+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}.
+
+## View to Model update
+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}.
+
+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.
+
+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`.
+
+
+
-
-
-