From 5e6ba2520174218d26defbe9488a1073da882072 Mon Sep 17 00:00:00 2001 From: Igor Minar Date: Mon, 12 Mar 2012 15:54:48 -0700 Subject: fix(forms): remove the need for extra form scope the forms/controls code refactored not to depend on events which forced us to create new scope for each form element. --- src/directive/form.js | 113 +++++++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 52 deletions(-) (limited to 'src/directive/form.js') diff --git a/src/directive/form.js b/src/directive/form.js index 96f7632b..27ba1044 100644 --- a/src/directive/form.js +++ b/src/directive/form.js @@ -22,49 +22,52 @@ * of `FormController`. * */ -FormController.$inject = ['$scope', 'name']; -function FormController($scope, name) { +FormController.$inject = ['$scope', 'name', '$element']; +function FormController($scope, name, element) { var form = this, + parentForm = element.parent().inheritedData('$formController'), errors = form.error = {}; // publish the form into scope name(this); - $scope.$on('$destroy', function(event, widget) { - if (!widget) return; + if (parentForm) { + parentForm.$addControl(form); + } - if (widget.widgetId && form[widget.widgetId] === widget) { - delete form[widget.widgetId]; + form.$addControl = function(control) { + if (control.name && !form.hasOwnProperty(control.name)) { + form[control.name] = control; } - 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; + form.$removeControl = function(control) { + if (control.name && form[control.name] === control) { + delete form[control.name]; } - }); + forEach(errors, cleanupControlErrors, control); + }; - $scope.$on('$invalid', function(event, error, widget) { - addWidget(error, widget); + form.$setValidity = function(validationToken, isValid, control) { + if (isValid) { + cleanupControlErrors(errors[validationToken], validationToken, control); - form.valid = false; - form.invalid = true; - }); + if (equals(errors, {})) { + form.valid = true; + form.invalid = false; + } + } else { + addControlError(validationToken, control); - $scope.$on('$viewTouch', function() { + form.valid = false; + form.invalid = true; + } + }; + + form.$setDirty = function() { form.dirty = true; form.pristine = false; - }); - - $scope.$on('$newFormControl', function(event, widget) { - if (widget.widgetId && !form.hasOwnProperty(widget.widgetId)) { - form[widget.widgetId] = widget; - } - }); + } // init state form.dirty = false; @@ -72,32 +75,40 @@ function FormController($scope, name) { form.valid = true; form.invalid = false; - function removeWidget(queue, errorKey, widget) { + function cleanupControlErrors(queue, validationToken, control) { if (queue) { - widget = widget || this; // so that we can be used in forEach; + control = control || this; // so that we can be used in forEach; for (var i = 0, length = queue.length; i < length; i++) { - if (queue[i] === widget) { + if (queue[i] === control) { queue.splice(i, 1); if (!queue.length) { - delete errors[errorKey]; + delete errors[validationToken]; + + if (parentForm) { + parentForm.$setValidity(validationToken, true, form); + } } } } } } - function addWidget(errorKey, widget) { - var queue = errors[errorKey]; + function addControlError(validationToken, control) { + var queue = errors[validationToken]; if (queue) { for (var i = 0, length = queue.length; i < length; i++) { - if (queue[i] === widget) { + if (queue[i] === control) { return; } } } else { - errors[errorKey] = queue = []; + errors[validationToken] = queue = []; + + if (parentForm) { + parentForm.$setValidity(validationToken, false, form); + } } - queue.push(widget); + queue.push(control); } } @@ -107,12 +118,12 @@ function FormController($scope, name) { * @name angular.module.ng.$compileProvider.directive.form * @restrict EA * - * @scope * @description * Directive that instantiates * {@link angular.module.ng.$compileProvider.directive.form.FormController FormController}. * - * If `name` attribute is specified, the controller is published to the scope as well. + * If `name` attribute is specified, the form controller is published onto the current scope under + * this name. * * # Alias: `ng-form` * @@ -164,28 +175,28 @@ function FormController($scope, name) {
- text: - Required! - text = {{text}}
- myForm.input.valid = {{myForm.input.valid}}
- myForm.input.error = {{myForm.input.error}}
- myForm.valid = {{myForm.valid}}
- myForm.error.REQUIRED = {{!!myForm.error.REQUIRED}}
+ userType: + Required!
+ userType = {{userType}}
+ myForm.input.valid = {{myForm.input.valid}}
+ myForm.input.error = {{myForm.input.error}}
+ myForm.valid = {{myForm.valid}}
+ myForm.error.REQUIRED = {{!!myForm.error.REQUIRED}}
it('should initialize to model', function() { - expect(binding('text')).toEqual('guest'); + expect(binding('userType')).toEqual('guest'); expect(binding('myForm.input.valid')).toEqual('true'); }); it('should be invalid if empty', function() { - input('text').enter(''); - expect(binding('text')).toEqual(''); + input('userType').enter(''); + expect(binding('userType')).toEqual(''); expect(binding('myForm.input.valid')).toEqual('false'); }); @@ -195,7 +206,6 @@ var formDirective = [function() { return { name: 'form', restrict: 'E', - scope: true, inject: { name: 'accessor' }, @@ -203,7 +213,6 @@ var formDirective = [function() { compile: function() { return { pre: function(scope, formElement, attr, controller) { - formElement.data('$form', controller); formElement.bind('submit', function(event) { if (!attr.action) event.preventDefault(); }); -- cgit v1.2.3