aboutsummaryrefslogtreecommitdiffstats
path: root/src/widget/form.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/widget/form.js')
-rw-r--r--src/widget/form.js134
1 files changed, 107 insertions, 27 deletions
diff --git a/src/widget/form.js b/src/widget/form.js
index deaf38d5..23b07107 100644
--- a/src/widget/form.js
+++ b/src/widget/form.js
@@ -1,5 +1,86 @@
'use strict';
+FormController.$inject = ['$scope', 'name'];
+function FormController($scope, name) {
+ var form = this,
+ errors = form.error = {};
+
+ // publish the form into scope
+ name(this);
+
+ $scope.$on('$destroy', function(event, widget) {
+ if (!widget) return;
+
+ if (widget.widgetId) {
+ delete form[widget.widgetId];
+ }
+ forEach(errors, removeWidget, widget);
+ });
+
+ $scope.$on('$valid', function(event, error, widget) {
+ removeWidget(errors[error], error, widget);
+
+ if (equals(errors, {})) {
+ form.valid = true;
+ form.invalid = false;
+ }
+ });
+
+ $scope.$on('$invalid', function(event, error, widget) {
+ addWidget(error, widget);
+
+ form.valid = false;
+ form.invalid = true;
+ });
+
+ $scope.$on('$viewTouch', function() {
+ form.dirty = true;
+ form.pristine = false;
+ });
+
+ // init state
+ form.dirty = false;
+ form.pristine = true;
+ form.valid = true;
+ form.invalid = false;
+
+ function removeWidget(queue, errorKey, widget) {
+ if (queue) {
+ widget = widget || this; // so that we can be used in forEach;
+ for (var i = 0, length = queue.length; i < length; i++) {
+ if (queue[i] === widget) {
+ queue.splice(i, 1);
+ if (!queue.length) {
+ delete errors[errorKey];
+ }
+ }
+ }
+ }
+ }
+
+ function addWidget(errorKey, widget) {
+ var queue = errors[errorKey];
+ if (queue) {
+ for (var i = 0, length = queue.length; i < length; i++) {
+ if (queue[i] === widget) {
+ return;
+ }
+ }
+ } else {
+ errors[errorKey] = queue = [];
+ }
+ queue.push(widget);
+ }
+}
+
+FormController.prototype.registerWidget = function(widget, alias) {
+ if (alias && !this.hasOwnProperty(alias)) {
+ widget.widgetId = alias;
+ this[alias] = widget;
+ }
+};
+
+
/**
* @ngdoc directive
* @name angular.module.ng.$compileProvider.directive.form
@@ -57,55 +138,54 @@
$scope.text = 'guest';
}
</script>
- <div ng:controller="Ctrl">
- <form name="myForm">
- text: <input type="text" name="input" ng:model="text" required>
- <span class="error" ng:show="myForm.text.$error.REQUIRED">Required!</span>
- </form>
+ <form name="myForm" ng:controller="Ctrl">
+ text: <input type="text" name="input" ng:model="text" required>
+ <span class="error" ng:show="myForm.input.error.REQUIRED">Required!</span>
<tt>text = {{text}}</tt><br/>
- <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
- <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
- <tt>myForm.$error.REQUIRED = {{!!myForm.$error.REQUIRED}}</tt><br/>
- </div>
+ <tt>myForm.input.valid = {{myForm.input.valid}}</tt><br/>
+ <tt>myForm.input.error = {{myForm.input.error}}</tt><br/>
+ <tt>myForm.valid = {{myForm.valid}}</tt><br/>
+ <tt>myForm.error.REQUIRED = {{!!myForm.error.REQUIRED}}</tt><br/>
+ </form>
</doc:source>
<doc:scenario>
it('should initialize to model', function() {
expect(binding('text')).toEqual('guest');
- expect(binding('myForm.input.$valid')).toEqual('true');
+ expect(binding('myForm.input.valid')).toEqual('true');
});
it('should be invalid if empty', function() {
input('text').enter('');
expect(binding('text')).toEqual('');
- expect(binding('myForm.input.$valid')).toEqual('false');
+ expect(binding('myForm.input.valid')).toEqual('false');
});
</doc:scenario>
</doc:example>
*/
-var ngFormDirective = ['$formFactory', function($formFactory) {
+var ngFormDirective = [function() {
return {
+ name: 'form',
restrict: 'E',
+ scope: true,
+ inject: {
+ name: 'accessor'
+ },
+ controller: FormController,
compile: function() {
return {
- pre: function(scope, formElement, attr) {
- var name = attr.name,
- parentForm = $formFactory.forElement(formElement),
- form = $formFactory(parentForm);
- formElement.data('$form', form);
- formElement.bind('submit', function(event){
+ pre: function(scope, formElement, attr, controller) {
+ formElement.data('$form', controller);
+ formElement.bind('submit', function(event) {
if (!attr.action) event.preventDefault();
});
- if (name) {
- scope[name] = form;
- }
- watch('valid');
- watch('invalid');
- function watch(name) {
- form.$watch('$' + name, function(value) {
+
+ forEach(['valid', 'invalid', 'dirty', 'pristine'], function(name) {
+ scope.$watch(function() {
+ return controller[name];
+ }, function(value) {
formElement[value ? 'addClass' : 'removeClass']('ng-' + name);
});
- }
+ });
}
};
}