From 4f78fd692c0ec51241476e6be9a4df06cd62fdd6 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 8 Sep 2011 13:56:29 -0700 Subject: feat(forms): new and improved forms --- .../guide/dev_guide.compiler.directives.ngdoc | 2 +- docs/content/guide/dev_guide.expressions.ngdoc | 27 +- docs/content/guide/dev_guide.forms.ngdoc | 610 +++++++++++++++++++++ .../dev_guide.mvc.understanding_controller.ngdoc | 4 +- .../guide/dev_guide.mvc.understanding_model.ngdoc | 2 +- docs/content/guide/dev_guide.overview.ngdoc | 44 +- .../guide/dev_guide.services.$location.ngdoc | 2 +- .../dev_guide.services.injecting_controllers.ngdoc | 4 +- .../guide/dev_guide.templates.css-styling.ngdoc | 52 +- ..._guide.templates.filters.creating_filters.ngdoc | 26 +- ....templates.formatters.creating_formatters.ngdoc | 55 -- .../guide/dev_guide.templates.formatters.ngdoc | 20 - ...ide.templates.formatters.using_formatters.ngdoc | 9 - docs/content/guide/dev_guide.templates.ngdoc | 9 +- ....templates.validators.creating_validators.ngdoc | 82 --- .../guide/dev_guide.templates.validators.ngdoc | 131 ----- docs/content/guide/index.ngdoc | 3 +- 17 files changed, 702 insertions(+), 380 deletions(-) create mode 100644 docs/content/guide/dev_guide.forms.ngdoc delete mode 100644 docs/content/guide/dev_guide.templates.formatters.creating_formatters.ngdoc delete mode 100644 docs/content/guide/dev_guide.templates.formatters.ngdoc delete mode 100644 docs/content/guide/dev_guide.templates.formatters.using_formatters.ngdoc delete mode 100644 docs/content/guide/dev_guide.templates.validators.creating_validators.ngdoc delete mode 100644 docs/content/guide/dev_guide.templates.validators.ngdoc (limited to 'docs/content/guide') diff --git a/docs/content/guide/dev_guide.compiler.directives.ngdoc b/docs/content/guide/dev_guide.compiler.directives.ngdoc index 0f99e46b..3b233551 100644 --- a/docs/content/guide/dev_guide.compiler.directives.ngdoc +++ b/docs/content/guide/dev_guide.compiler.directives.ngdoc @@ -16,7 +16,7 @@ directives per element. You add angular directives to a standard HTML tag as in the following example, in which we have added the {@link api/angular.directive.ng:click ng:click} directive to a button tag: - + In the example above, `name` is the standard HTML attribute, and `ng:click` is the angular directive. The `ng:click` directive lets you implement custom behavior in an associated controller diff --git a/docs/content/guide/dev_guide.expressions.ngdoc b/docs/content/guide/dev_guide.expressions.ngdoc index 177a5e87..ab5a897b 100644 --- a/docs/content/guide/dev_guide.expressions.ngdoc +++ b/docs/content/guide/dev_guide.expressions.ngdoc @@ -51,9 +51,15 @@ You can try evaluating different expressions here: -
+ +
Expression: - +
  • @@ -84,9 +90,18 @@ the global state (a common source of subtle bugs). -
    - Name: - + +
    + Name: +
    @@ -158,7 +173,7 @@ Extensions: You can further extend the expression vocabulary by adding new metho {name:'Mike', phone:'555-4321'}, {name:'Adam', phone:'555-5678'}, {name:'Julie', phone:'555-8765'}]">
    - Search: + Search: diff --git a/docs/content/guide/dev_guide.forms.ngdoc b/docs/content/guide/dev_guide.forms.ngdoc new file mode 100644 index 00000000..6849ff4e --- /dev/null +++ b/docs/content/guide/dev_guide.forms.ngdoc @@ -0,0 +1,610 @@ +@ngdoc overview +@name Developer Guide: Forms +@description + +# Overview + +Forms allow users to enter data into your application. Forms represent the bidirectional data +bindings in Angular. + +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 + + +# Form + +A form groups a set of widgets together into a single logical data-set. A form is created using +the {@link api/angular.widget.form <form>} element that calls the +{@link api/angular.service.$formFactory $formFactory} service. The form is responsible for managing +the widgets and for tracking validation information. + +A form is: + +- 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.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: + + - `$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. + + - `$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 ]`. + + +# 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.widget.input input} and +{@link api/angular.widget.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.service.$formFactory $formFactory.rootForm} form is used. + +Widgets are implemented as Angular controllers. A widget controller: + +- implements methods: + + - `$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) + +- 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. + + +# CSS + +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}) + + +# Example + +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. + + + + + + +
    + +
    + +
    + + + Customer name is required! +

    + + +
    +
    + , + +

    + + + Incomplete address: +
    + Missing state! +
    + Invalid state! +
    + Missing zip! +
    + Invalid zip! + + + + + + + +
    + Debug View: +
    form={{form}}
    +
    master={{master}}
    +
    userForm={{userForm}}
    +
    addressForm={{addressForm}}
    +
    + + + it('should enable save button', function(){ + expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy(); + input('form.customer').enter(''); + expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy(); + input('form.customer').enter('change'); + expect(element(':button:contains(Save)').attr('disabled')).toBeFalsy(); + element(':button:contains(Save)').click(); + expect(element(':button:contains(Save)').attr('disabled')).toBeTruthy(); + }); + it('should enable cancel button', function(){ + expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy(); + input('form.customer').enter('change'); + expect(element(':button:contains(Cancel)').attr('disabled')).toBeFalsy(); + element(':button:contains(Cancel)').click(); + expect(element(':button:contains(Cancel)').attr('disabled')).toBeTruthy(); + expect(element(':input[ng\\:model="form.customer"]').val()).toEqual('John Smith'); + }); + + + +# Life-cycle + +- The `
    ` element triggers creation of a new form {@link dev_guide.scopes scope} using the + {@link api/angular.service.$formFactory $formfactory}. The new form scope is added to the + `` element using the jQuery `.data()` method for later retrieval under the key `$form`. + The form also sets up these listeners: + + - `$destroy` - This event is emitted by nested widget when it is removed from the view. It gives + the form a chance to clean up any validation references to the destroyed widget. + - `$valid` / `$invalid` - This event is emitted by the widget on validation state change. + +- `` element triggers the creation of the widget using the + {@link api/angular.service.$formFactory $formfactory.$createWidget()} method. The `$createWidget()` + creates new widget instance by calling the current scope {@link api/angular.scope.$new .$new()} and + registers these listeners: + + - `$watch` on the model scope. + - `$viewChange` event on the widget scope. + - `$validate` event on the widget scope. + - Element `change` event when the user enters data. + + + + +- When the user interacts with the widget: + + 1. The DOM element fires the `change` event which the widget intercepts. Widget then emits + a `$viewChange` event which includes the new user-entered value. (Remember that the DOM events + are outside of the Angular environment so the widget must emit its event within the + {@link api/angular.scope.$apply $apply} method). + 2. The form's `$viewChange` listener copies the user-entered value to the widget's `$viewValue` + property. Since the `$viewValue` is the raw value as entered by user, it may need to be + translated to a different format/type (for example, translating a string to a number). + If you need your widget to translate between the internal `$viewValue` and the external + `$modelValue` state, you must declare a `$parseView()` method. The `$parseView()` method + will copy `$viewValue` to `$modelValue` and perform any necessary translations. + 3. The `$modelValue` is written into the application model. + 4. The form then emits a `$validate` event, giving the widget's validators chance to validate the + input. There can be any number of validators registered. Each validator may in turn + emit a `$valid` / `$invalid` event with the validator's validation key. For example `REQUIRED`. + 5. Form listens to `$valid`/`$invalid` events and updates both the form as well as the widget + scope with the validation state. The validation updates the `$valid` and `$invalid`, property + as well as `$error` object. The widget's `$error` object is updated with the validation key + such that `$error.REQUIRED == true` when the validation emits `$invalid` with `REQUIRED` + validation key. Similarly the form's `$error` object gets updated, but instead of boolean + `true` it contains an array of invalid widgets (widgets which fired `$invalid` event with + `REQUIRED` validation key). + +- When the model is updated: + + 1. The model `$watch` listener assigns the model value to `$modelValue` on the widget. + 2. The form then calls `$parseModel` method on widget if present. The method converts the + value to renderable format and assigns it to `$viewValue` (for example converting number to a + string.) + 3. The form then emits a `$validate` which behaves as described above. + 4. The form then calls `$render` method on the widget to update the DOM structure from the + `$viewValue`. + + + +# Writing Your Own Widget + +This example shows how to implement a custom HTML editor widget in Angular. + + + + + +
    +
    + HTML:
    + +
    +
    editorForm = {{editorForm}}
    + +
    + + it('should enter invalid HTML', function(){ + expect(element('form[name=editorForm]').prop('className')).toMatch(/ng-valid/); + input('htmlContent').enter('<'); + expect(element('form[name=editorForm]').prop('className')).toMatch(/ng-invalid/); + }); + +
    + + + +# HTML Inputs + +The most common widgets you will use will be in the form of the +standard HTML set. These widgets are bound using the `name` attribute +to an expression. In addition, they can have `required` attribute to further control their +validation. + + + +
    NamePhone
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameFormatHTMLUI{{input#}}
    textString<input type="text" ng:model="input1">{{input1|json}}
    textareaString<textarea ng:model="input2"></textarea>{{input2|json}}
    radioString + <input type="radio" ng:model="input3" value="A">
    + <input type="radio" ng:model="input3" value="B"> +
    + + + {{input3|json}}
    checkboxBoolean<input type="checkbox" ng:model="input4">{{input4|json}}
    pulldownString + <select ng:model="input5">
    +   <option value="c">C</option>
    +   <option value="d">D</option>
    + </select>
    +
    + + {{input5|json}}
    multiselectArray + <select ng:model="input6" multiple size="4">
    +   <option value="e">E</option>
    +   <option value="f">F</option>
    + </select>
    +
    + + {{input6|json}}
    +
    + + + it('should exercise text', function(){ + input('input1').enter('Carlos'); + expect(binding('input1')).toEqual('"Carlos"'); + }); + it('should exercise textarea', function(){ + input('input2').enter('Carlos'); + expect(binding('input2')).toEqual('"Carlos"'); + }); + it('should exercise radio', function(){ + expect(binding('input3')).toEqual('"A"'); + input('input3').select('B'); + expect(binding('input3')).toEqual('"B"'); + input('input3').select('A'); + expect(binding('input3')).toEqual('"A"'); + }); + it('should exercise checkbox', function(){ + expect(binding('input4')).toEqual('false'); + input('input4').check(); + expect(binding('input4')).toEqual('true'); + }); + it('should exercise pulldown', function(){ + expect(binding('input5')).toEqual('"c"'); + select('input5').option('d'); + expect(binding('input5')).toEqual('"d"'); + }); + it('should exercise multiselect', function(){ + expect(binding('input6')).toEqual('[]'); + select('input6').options('e'); + expect(binding('input6')).toEqual('["e"]'); + select('input6').options('e', 'f'); + expect(binding('input6')).toEqual('["e","f"]'); + }); + +
    + +#Testing + +When unit-testing a controller it may be desirable to have a reference to form and to simulate +different form validation states. + +This example demonstrates a login form, where the login button is enabled only when the form is +properly filled out. +
    +  
    +
    + + +
    +
    + +In the unit tests we do not have access to the DOM, and therefore the `loginForm` reference does +not get set on the controller. This example shows how it can be unit-tested, by creating a mock +form. +
    +function LoginController() {
    +  this.disableLogin = function() {
    +    return this.loginForm.$invalid;
    +  };
    +}
    +
    +describe('LoginController', function() {
    +  it('should disable login button when form is invalid', function() {
    +    var scope = angular.scope();
    +    var loginController = scope.$new(LoginController);
    +
    +    // In production the 'loginForm' form instance gets set from the view,
    +    // but in unit-test we have to set it manually.
    +    loginController.loginForm = scope.$service('$formFactory')();
    +
    +    expect(loginController.disableLogin()).toBe(false);
    +
    +    // Now simulate an invalid form
    +    loginController.loginForm.$emit('$invalid', 'MyReason');
    +    expect(loginController.disableLogin()).toBe(true);
    +
    +    // Now simulate a valid form
    +    loginController.loginForm.$emit('$valid', 'MyReason');
    +    expect(loginController.disableLogin()).toBe(false);
    +  });
    +});
    +
    + +## Custom widgets + +This example demonstrates a login form, where the password has custom validation rules. +
    +  
    +
    + + +
    +
    + +In the unit tests we do not have access to the DOM, and therefore the `loginForm` and custom +input type reference does not get set on the controller. This example shows how it can be +unit-tested, by creating a mock form and a mock custom input type. +
    +function LoginController(){
    +  this.disableLogin = function() {
    +    return this.loginForm.$invalid;
    +  };
    +
    +  this.StrongPassword = function(element) {
    +    var widget = this;
    +    element.attr('type', 'password'); // act as password.
    +    this.$on('$validate', function(){
    +      widget.$emit(widget.$viewValue.length > 5 ? '$valid' : '$invalid', 'PASSWORD');
    +    });
    +  };
    +}
    +
    +describe('LoginController', function() {
    +  it('should disable login button when form is invalid', function() {
    +    var scope = angular.scope();
    +    var loginController = scope.$new(LoginController);
    +    var input = angular.element('');
    +
    +    // In production the 'loginForm' form instance gets set from the view,
    +    // but in unit-test we have to set it manually.
    +    loginController.loginForm = scope.$service('$formFactory')();
    +
    +    // now instantiate a custom input type
    +    loginController.loginForm.$createWidget({
    +      scope: loginController,
    +      model: 'password',
    +      alias: 'password',
    +      controller: loginController.StrongPassword,
    +      controllerArgs: [input]
    +    });
    +
    +    // Verify that the custom password input type sets the input type to password
    +    expect(input.attr('type')).toEqual('password');
    +
    +    expect(loginController.disableLogin()).toBe(false);
    +
    +    // Now simulate an invalid form
    +    loginController.loginForm.password.$emit('$invalid', 'PASSWORD');
    +    expect(loginController.disableLogin()).toBe(true);
    +
    +    // Now simulate a valid form
    +    loginController.loginForm.password.$emit('$valid', 'PASSWORD');
    +    expect(loginController.disableLogin()).toBe(false);
    +
    +    // Changing model state, should also influence the form validity
    +    loginController.password = 'abc'; // too short so it should be invalid
    +    scope.$digest();
    +    expect(loginController.loginForm.password.$invalid).toBe(true);
    +
    +    // Changeing model state, should also influence the form validity
    +    loginController.password = 'abcdef'; // should be valid
    +    scope.$digest();
    +    expect(loginController.loginForm.password.$valid).toBe(true);
    +  });
    +});
    +
    + + diff --git a/docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc b/docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc index 15ae3b34..7a6653e9 100644 --- a/docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc +++ b/docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc @@ -68,7 +68,7 @@ Putting any presentation logic into controllers significantly affects testabilit logic. Angular offers {@link dev_guide.templates.databinding} for automatic DOM manipulation. If you have to perform your own manual DOM manipulation, encapsulate the presentation logic in {@link dev_guide.compiler.widgets widgets} and {@link dev_guide.compiler.directives directives}. -- Input formatting — Use {@link dev_guide.templates.formatters angular formatters} instead. +- Input formatting — Use {@link dev_guide.forms angular form widgets} instead. - Output filtering — Use {@link dev_guide.templates.filters angular filters} instead. - Run stateless or stateful code shared across controllers — Use {@link dev_guide.services angular services} instead. @@ -139,7 +139,7 @@ previous example.
     
    - 
    + 
      
      
      

    The food is {{spice}} spicy!

    diff --git a/docs/content/guide/dev_guide.mvc.understanding_model.ngdoc b/docs/content/guide/dev_guide.mvc.understanding_model.ngdoc index a35541d0..b4659b0c 100644 --- a/docs/content/guide/dev_guide.mvc.understanding_model.ngdoc +++ b/docs/content/guide/dev_guide.mvc.understanding_model.ngdoc @@ -41,7 +41,7 @@ when processing the following template constructs: * Form input, select, textarea and other form elements: - + The code above creates a model called "query" on the current scope with the value set to "fluffy cloud". diff --git a/docs/content/guide/dev_guide.overview.ngdoc b/docs/content/guide/dev_guide.overview.ngdoc index f5db7f94..fcf15044 100644 --- a/docs/content/guide/dev_guide.overview.ngdoc +++ b/docs/content/guide/dev_guide.overview.ngdoc @@ -42,19 +42,27 @@ easier a web developer's life can if they're using angular: - Invoice: -
    -
    - - - - - - - -
    QuantityCost
    -
    - Total: {{qty * cost | currency}} + +
    + Invoice: +
    +
    + + + + + + + +
    QuantityCost
    +
    + Total: {{qty * cost | currency}} +
    - +
     // js - controller
    diff --git a/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc b/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc
    index 0046dd7f..44206f7c 100644
    --- a/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc
    +++ b/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc
    @@ -54,13 +54,13 @@ myController.$inject = ['notify'];
     
     

    Let's try this simple notify service, injected into the controller...

    - +
    it('should test service', function(){ - expect(element(':input[name=message]').val()).toEqual('test'); + expect(element(':input[ng\\:model="message"]').val()).toEqual('test'); }); diff --git a/docs/content/guide/dev_guide.templates.css-styling.ngdoc b/docs/content/guide/dev_guide.templates.css-styling.ngdoc index 4a4b2d65..4bd3f1b2 100644 --- a/docs/content/guide/dev_guide.templates.css-styling.ngdoc +++ b/docs/content/guide/dev_guide.templates.css-styling.ngdoc @@ -4,48 +4,32 @@ @description -Angular includes built-in CSS classes, which in turn have predefined CSS styles. +Angular sets these CSS classes. It is up to your application to provide useful styling. -# Built-in CSS classes +# CSS classes used by angular -* `ng-exception` +* `ng-invalid`, `ng-valid` + - **Usage:** angular applies this class to an input widget element if that element's input does + notpass validation. (see {@link api/angular.widget.input input} widget). -**Usage:** angular applies this class to a DOM element if that element contains an Expression that -threw an exception when evaluated. +* `ng-pristine`, `ng-dirty` + - **Usage:** angular {@link api/angular.widget.input input} widget applies `ng-pristine` class + to a new input widget element which did not have user interaction. Once the user interacts with + the input widget the class is changed to `ng-dirty`. -**Styling:** The built-in styling of the ng-exception class displays an error message surrounded -by a solid red border, for example: +# Marking CSS classes -
    Error message
    +* `ng-widget`, `ng-directive` + - **Usage:** angular sets these class on elements where {@link api/angular.widget widget} or + {@link api/angular.directive directive} has bound to. -You can try to evaluate malformed expressions in {@link dev_guide.expressions expressions} to see -the `ng-exception` class' styling. - -* `ng-validation-error` - -**Usage:** angular applies this class to an input widget element if that element's input does not -pass validation. Note that you set the validation criteria on the input widget element using the -Ng:validate or Ng:required directives. - -**Styling:** The built-in styling of the ng-validation-error class turns the border of the input -box red and includes a hovering UI element that includes more details of the validation error. You -can see an example in {@link api/angular.widget.@ng:validate ng:validate example}. - -## Overriding Styles for Angular CSS Classes - -To override the styles for angular's built-in CSS classes, you can do any of the following: - -* Download the source code, edit angular.css, and host the source on your own server. -* Create a local CSS file, overriding any styles that you'd like, and link to it from your HTML file -as you normally would: - -
    -
    -
    +* Old browser support + - Pre v9, IE browsers could not select `ng:include` elements in CSS, because of the `:` + character. For this reason angular also sets `ng-include` class on any element which has `:` + character in the name by replacing `:` with `-`. ## Related Topics * {@link dev_guide.templates Angular Templates} -* {@link dev_guide.templates.formatters Angular Formatters} -* {@link dev_guide.templates.formatters.creating_formatters Creating Angular Formatters} +* {@link dev_guide.forms Angular Forms} diff --git a/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc b/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc index ebb7d923..27daec9f 100644 --- a/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc +++ b/docs/content/guide/dev_guide.templates.filters.creating_filters.ngdoc @@ -35,20 +35,26 @@ text upper-case and assigns color. } return out; }); + + function Ctrl(){ + this.greeting = 'hello'; + } -
    -No filter: {{text}}
    -Reverse: {{text|reverse}}
    -Reverse + uppercase: {{text|reverse:true}}
    -Reverse + uppercase + blue: {{text|reverse:true:"blue"}} +
    +
    + No filter: {{greeting}}
    + Reverse: {{greeting|reverse}}
    + Reverse + uppercase: {{greeting|reverse:true}}
    + Reverse + uppercase + blue: {{greeting|reverse:true:"blue"}} +
    -it('should reverse text', function(){ -expect(binding('text|reverse')).toEqual('olleh'); -input('text').enter('ABC'); -expect(binding('text|reverse')).toEqual('CBA'); -}); + it('should reverse greeting', function(){ + expect(binding('greeting|reverse')).toEqual('olleh'); + input('greeting').enter('ABC'); + expect(binding('greeting|reverse')).toEqual('CBA'); + }); diff --git a/docs/content/guide/dev_guide.templates.formatters.creating_formatters.ngdoc b/docs/content/guide/dev_guide.templates.formatters.creating_formatters.ngdoc deleted file mode 100644 index 2ecd8f19..00000000 --- a/docs/content/guide/dev_guide.templates.formatters.creating_formatters.ngdoc +++ /dev/null @@ -1,55 +0,0 @@ -@workInProgress -@ngdoc overview -@name Developer Guide: Templates: Angular Formatters: Creating Angular Formatters -@description - -To create your own formatter, you can simply register a pair of JavaScript functions with -`angular.formatter`. One of your functions is used to parse text from the input widget into the -data storage format; the other function is used to format stored data into user-readable text. - -The following example demonstrates a "reverse" formatter. Data is stored in uppercase and in -reverse, but it is displayed in lower case and non-reversed. When a user edits the data model via -the input widget, the input is automatically parsed into the internal data storage format, and when -the data changes in the model, it is automatically formatted to the user-readable form for display -in the view. - -
    -function reverse(text) {
    -var reversed = [];
    -for (var i = 0; i < text.length; i++) {
    -reversed.unshift(text.charAt(i));
    -}
    -return reversed.join('');
    -}
    -
    -angular.formatter('reverse', {
    -parse: function(value){
    -return reverse(value||'').toUpperCase();
    -},
    -format: function(value){
    -return reverse(value||'').toLowerCase();
    -}
    -});
    -
    - - - - - diff --git a/docs/content/guide/dev_guide.templates.formatters.ngdoc b/docs/content/guide/dev_guide.templates.formatters.ngdoc deleted file mode 100644 index 82a14fb4..00000000 --- a/docs/content/guide/dev_guide.templates.formatters.ngdoc +++ /dev/null @@ -1,20 +0,0 @@ -@workInProgress -@ngdoc overview -@name Developer Guide: Templates: Angular Formatters -@description - -In angular, formatters are responsible for translating user-readable text entered in an {@link -api/angular.widget.HTML input widget} to a JavaScript object in the data model that the application -can manipulate. - -You can use formatters in a template, and also in JavaScript. Angular provides built-in -formatters, and of course you can create your own formatters. - -## Related Topics - -* {@link dev_guide.templates.formatters.using_formatters Using Angular Formatters} -* {@link dev_guide.templates.formatters.creating_formatters Creating Angular Formatters} - -## Related API - -* {@link api/angular.formatter Angular Formatter API} diff --git a/docs/content/guide/dev_guide.templates.formatters.using_formatters.ngdoc b/docs/content/guide/dev_guide.templates.formatters.using_formatters.ngdoc deleted file mode 100644 index bf983cd5..00000000 --- a/docs/content/guide/dev_guide.templates.formatters.using_formatters.ngdoc +++ /dev/null @@ -1,9 +0,0 @@ -@workInProgress -@ngdoc overview -@name Developer Guide: Templates: Angular Formatters: Using Angular Formatters -@description - -The following snippet shows how to use a formatter in a template. The formatter below is -`ng:format="reverse"`, added as an attribute to an `` tag. - -
    diff --git a/docs/content/guide/dev_guide.templates.ngdoc b/docs/content/guide/dev_guide.templates.ngdoc
    index ca0ca99a..32514eb9 100644
    --- a/docs/content/guide/dev_guide.templates.ngdoc
    +++ b/docs/content/guide/dev_guide.templates.ngdoc
    @@ -18,9 +18,7 @@ is {@link api/angular.widget.@ng:repeat ng:repeat}.
     * {@link dev_guide.compiler.markup  Markup} — Shorthand for a widget or a directive. The double
     curly brace notation `{{ }}` to bind expressions to elements is built-in angular markup.
     * {@link dev_guide.templates.filters Filter} — Formats your data for display to the user.
    -* {@link dev_guide.templates.validators Validator} — Lets you validate user input.
    -* {@link dev_guide.templates.formatters Formatter} — Lets you format the input object into a user
    -readable view.
    +* {@link dev_guide.forms Form widgets} — Lets you validate user input.
     
     Note:  In addition to declaring the elements above in templates, you can also access these elements
     in JavaScript code.
    @@ -33,7 +31,7 @@ and {@link dev_guide.expressions expressions}:
     
      
      
    -   
    +   
        
    @@ -55,8 +53,7 @@ eight.
     ## Related Topics
     
     * {@link dev_guide.templates.filters Angular Filters}
    -* {@link dev_guide.templates.formatters Angular Formatters}
    -* {@link dev_guide.templates.validators Angular Validators}
    +* {@link dev_guide.forms Angular Forms}
     
     ## Related API
     
    diff --git a/docs/content/guide/dev_guide.templates.validators.creating_validators.ngdoc b/docs/content/guide/dev_guide.templates.validators.creating_validators.ngdoc
    deleted file mode 100644
    index 835b0b51..00000000
    --- a/docs/content/guide/dev_guide.templates.validators.creating_validators.ngdoc
    +++ /dev/null
    @@ -1,82 +0,0 @@
    -@workInProgress
    -@ngdoc overview
    -@name Developer Guide: Validators: Creating Angular Validators
    -@description
    -
    -
    -To create a custom validator, you simply add your validator code as a method onto the
    -`angular.validator` object and provide input(s) for the validator function. Each input provided is
    -treated as an argument to the validator function.  Any additional inputs should be separated by
    -commas.
    -
    -The following bit of pseudo-code shows how to set up a custom validator:
    -
    -
    -angular.validator('your_validator', function(input [,additional params]) {
    -        [your validation code];
    -        if ( [validation succeeds] ) {
    -                return false;
    -        } else {
    -                return true; // No error message specified
    -                         }
    -}
    -
    - -Note that this validator returns "true" when the user's input is incorrect, as in "Yes, it's true, -there was a problem with that input". If you prefer to provide more information when a validator -detects a problem with input, you can specify an error message in the validator that angular will -display when the user hovers over the input widget. - -To specify an error message, replace "`return true;`" with an error string, for example: - - return "Must be a value between 1 and 5!"; - -Following is a sample UPS Tracking Number validator: - - - - - - - -it('should validate correct UPS tracking number', function() { -expect(element('input[name=trackNo]').attr('class')). - not().toMatch(/ng-validation-error/); -}); - -it('should not validate in correct UPS tracking number', function() { -input('trackNo').enter('foo'); -expect(element('input[name=trackNo]').attr('class')). - toMatch(/ng-validation-error/); -}); - - - -In this sample validator, we specify a regular expression against which to test the user's input. -Note that when the user's input matches `regexp`, the function returns "false" (""); otherwise it -returns the specified error message ("true"). - -Note: you can also access the current angular scope and DOM element objects in your validator -functions as follows: - -* `this` === The current angular scope. -* `this.$element` === The DOM element that contains the binding. This allows the filter to -manipulate the DOM in addition to transforming the input. - - -## Related Topics - -* {@link dev_guide.templates Angular Templates} -* {@link dev_guide.templates.filters Angular Filters} -* {@link dev_guide.templates.formatters Angular Formatters} - -## Related API - -* {@link api/angular.validator API Validator Reference} diff --git a/docs/content/guide/dev_guide.templates.validators.ngdoc b/docs/content/guide/dev_guide.templates.validators.ngdoc deleted file mode 100644 index 76df92b5..00000000 --- a/docs/content/guide/dev_guide.templates.validators.ngdoc +++ /dev/null @@ -1,131 +0,0 @@ -@workInProgress -@ngdoc overview -@name Developer Guide: Templates: Understanding Angular Validators -@description - -Angular validators are attributes that test the validity of different types of user input. Angular -provides a set of built-in input validators: - -* {@link api/angular.validator.phone phone number} -* {@link api/angular.validator.number number} -* {@link api/angular.validator.integer integer} -* {@link api/angular.validator.date date} -* {@link api/angular.validator.email email address} -* {@link api/angular.validator.json JSON} -* {@link api/angular.validator.regexp regular expressions} -* {@link api/angular.validator.url URLs} -* {@link api/angular.validator.asynchronous asynchronous} - -You can also create your own custom validators. - -# Using Angular Validators - -You can use angular validators in HTML template bindings, and in JavaScript: - -* Validators in HTML Template Bindings - -
    -
    -
    - -* Validators in JavaScript - -
    -angular.validator.[validator_type](parameters)
    -
    - -The following example shows how to use the built-in angular integer validator: - - - - Change me: - - - it('should validate the default number string', function() { - expect(element('input[name=number]').attr('class')). - not().toMatch(/ng-validation-error/); - }); - it('should not validate "foo"', function() { - input('number').enter('foo'); - expect(element('input[name=number]').attr('class')). - toMatch(/ng-validation-error/); - }); - - - -# Creating an Angular Validator - -To create a custom validator, you simply add your validator code as a method onto the -`angular.validator` object and provide input(s) for the validator function. Each input provided is -treated as an argument to the validator function. Any additional inputs should be separated by -commas. - -The following bit of pseudo-code shows how to set up a custom validator: - -
    -angular.validator('your_validator', function(input [,additional params]) {
    -        [your validation code];
    -        if ( [validation succeeds] ) {
    -                return false;
    -        } else {
    -                return true; // No error message specified
    -                          }
    -}
    -
    - -Note that this validator returns "true" when the user's input is incorrect, as in "Yes, it's true, -there was a problem with that input". If you prefer to provide more information when a validator -detects a problem with input, you can specify an error message in the validator that angular will -display when the user hovers over the input widget. - -To specify an error message, replace "`return true;`" with an error string, for example: - - return "Must be a value between 1 and 5!"; - -Following is a sample UPS Tracking Number validator: - - - - - - - -it('should validate correct UPS tracking number', function() { - expect(element('input[name=trackNo]').attr('class')). - not().toMatch(/ng-validation-error/); -}); - -it('should not validate in correct UPS tracking number', function() { - input('trackNo').enter('foo'); - expect(element('input[name=trackNo]').attr('class')). - toMatch(/ng-validation-error/); -}); - - - -In this sample validator, we specify a regular expression against which to test the user's input. -Note that when the user's input matches `regexp`, the function returns "false" (""); otherwise it -returns the specified error message ("true"). - -Note: you can also access the current angular scope and DOM element objects in your validator -functions as follows: - -* `this` === The current angular scope. -* `this.$element` === The DOM element that contains the binding. This allows the filter to -manipulate the DOM in addition to transforming the input. - - -## Related Topics - -* {@link dev_guide.templates Angular Templates} - -## Related API - -* {@link api/angular.validator Validator API} diff --git a/docs/content/guide/index.ngdoc b/docs/content/guide/index.ngdoc index b2aab161..8d609afa 100644 --- a/docs/content/guide/index.ngdoc +++ b/docs/content/guide/index.ngdoc @@ -42,8 +42,7 @@ of the following documents before returning here to the Developer Guide: ## {@link dev_guide.templates Angular Templates} * {@link dev_guide.templates.filters Understanding Angular Filters} -* {@link dev_guide.templates.formatters Understanding Angular Formatters} -* {@link dev_guide.templates.validators Understanding Angular Validators} +* {@link dev_guide.forms Understanding Angular Forms} ## {@link dev_guide.services Angular Services} -- cgit v1.2.3