Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit f8a07dd

Browse files
committed
refactor(form, ngModel): streamline how controls are added to parent forms
This delegates setting the control's parentForm to the parentForm's $addControl method. This way, the model controller saves one instance of looking up the parentForm controller. The form controller keeps two lookups (one for its own ctrl, one for the optional parent). This also fixes adding the parentForm in the following case: - a control is removed from a parent, but its corresponding DOM element is not destroyed - the control is then re-added to the form Before the fix, the control's parentForm was only set once during controller initialization, so the the parentForm would not be set on the control in that specific case.
1 parent 6f39f10 commit f8a07dd

File tree

3 files changed

+20
-18
lines changed

3 files changed

+20
-18
lines changed

src/ng/directive/form.js

+12-9
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
6565
var form = this,
6666
controls = [];
6767

68-
var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl;
69-
7068
// init state
7169
form.$error = {};
7270
form.$$success = {};
@@ -77,8 +75,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
7775
form.$valid = true;
7876
form.$invalid = false;
7977
form.$submitted = false;
80-
81-
parentForm.$addControl(form);
78+
form.$$parentForm = nullFormCtrl;
8279

8380
/**
8481
* @ngdoc method
@@ -132,6 +129,8 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
132129
if (control.$name) {
133130
form[control.$name] = control;
134131
}
132+
133+
control.$$parentForm = form;
135134
};
136135

137136
// Private API: rename a form control
@@ -205,7 +204,6 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
205204
delete object[property];
206205
}
207206
},
208-
parentForm: parentForm,
209207
$animate: $animate
210208
});
211209

@@ -224,7 +222,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
224222
$animate.addClass(element, DIRTY_CLASS);
225223
form.$dirty = true;
226224
form.$pristine = false;
227-
parentForm.$setDirty();
225+
form.$$parentForm.$setDirty();
228226
};
229227

230228
/**
@@ -280,7 +278,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
280278
form.$setSubmitted = function() {
281279
$animate.addClass(element, SUBMITTED_CLASS);
282280
form.$submitted = true;
283-
parentForm.$setSubmitted();
281+
form.$$parentForm.$setSubmitted();
284282
};
285283
}
286284

@@ -454,6 +452,7 @@ var formDirectiveFactory = function(isNgForm) {
454452
var formDirective = {
455453
name: 'form',
456454
restrict: isNgForm ? 'EAC' : 'E',
455+
require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
457456
controller: FormController,
458457
compile: function ngFormCompile(formElement, attr) {
459458
// Setup initial state of the control
@@ -462,7 +461,9 @@ var formDirectiveFactory = function(isNgForm) {
462461
var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
463462

464463
return {
465-
pre: function ngFormPreLink(scope, formElement, attr, controller) {
464+
pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
465+
var controller = ctrls[0];
466+
466467
// if `action` attr is not present on the form, prevent the default action (submission)
467468
if (!('action' in attr)) {
468469
// we can't use jq events because if a form is destroyed during submission the default
@@ -491,7 +492,9 @@ var formDirectiveFactory = function(isNgForm) {
491492
});
492493
}
493494

494-
var parentFormCtrl = controller.$$parentForm;
495+
var parentFormCtrl = ctrls[1] || controller.$$parentForm;
496+
parentFormCtrl.$addControl(controller);
497+
495498
var setter = nameAttr ? getSetter(controller.$name) : noop;
496499

497500
if (nameAttr) {

src/ng/directive/ngModel.js

+5-8
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
236236
this.$$success = {}; // keep valid keys here
237237
this.$pending = undefined; // keep pending keys here
238238
this.$name = $interpolate($attr.name || '', false)($scope);
239-
239+
this.$$parentForm = nullFormCtrl;
240240

241241
var parsedNgModel = $parse($attr.ngModel),
242242
parsedNgModelAssign = parsedNgModel.assign,
@@ -316,8 +316,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
316316
return isUndefined(value) || value === '' || value === null || value !== value;
317317
};
318318

319-
var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
320-
currentValidationRunId = 0;
319+
var currentValidationRunId = 0;
321320

322321
/**
323322
* @ngdoc method
@@ -350,7 +349,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
350349
unset: function(object, property) {
351350
delete object[property];
352351
},
353-
parentForm: parentForm,
354352
$animate: $animate
355353
});
356354

@@ -388,7 +386,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
388386
ctrl.$pristine = false;
389387
$animate.removeClass($element, PRISTINE_CLASS);
390388
$animate.addClass($element, DIRTY_CLASS);
391-
parentForm.$setDirty();
389+
ctrl.$$parentForm.$setDirty();
392390
};
393391

394392
/**
@@ -1031,7 +1029,7 @@ var ngModelDirective = ['$rootScope', function($rootScope) {
10311029
return {
10321030
pre: function ngModelPreLink(scope, element, attr, ctrls) {
10331031
var modelCtrl = ctrls[0],
1034-
formCtrl = ctrls[1] || nullFormCtrl;
1032+
formCtrl = ctrls[1] || modelCtrl.$$parentForm;
10351033

10361034
modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
10371035

@@ -1267,7 +1265,6 @@ function addSetValidityMethod(context) {
12671265
classCache = {},
12681266
set = context.set,
12691267
unset = context.unset,
1270-
parentForm = context.parentForm,
12711268
$animate = context.$animate;
12721269

12731270
classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
@@ -1319,7 +1316,7 @@ function addSetValidityMethod(context) {
13191316
}
13201317

13211318
toggleValidationCss(validationErrorKey, combinedState);
1322-
parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
1319+
ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
13231320
}
13241321

13251322
function createAndSet(name, value, controller) {

test/ng/directive/ngModelSpec.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ describe('ngModel', function() {
1919
};
2020

2121
element = jqLite('<form><input></form>');
22-
element.data('$formController', parentFormCtrl);
2322

2423
scope = $rootScope;
2524
ngModelAccessor = jasmine.createSpy('ngModel accessor');
@@ -28,6 +27,9 @@ describe('ngModel', function() {
2827
$element: element.find('input'),
2928
$attrs: attrs
3029
});
30+
31+
//Assign the mocked parentFormCtrl to the model controller
32+
ctrl.$$parentForm = parentFormCtrl;
3133
}));
3234

3335

0 commit comments

Comments
 (0)