Skip to content

Commit a16520c

Browse files
shahatabtford
authored andcommitted
fix(formController): do not let removed controls affect forms
Closes angular#9035
1 parent 42e4f2a commit a16520c

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

src/ng/directive/form.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,17 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
7171
form.$invalid = false;
7272
form.$submitted = false;
7373

74+
// Setup initial state of the control
75+
element.addClass(PRISTINE_CLASS);
76+
77+
this.$$setParentForm = function(form) {
78+
parentForm = form;
79+
};
80+
81+
this.$$getParentForm = function(form) {
82+
return parentForm;
83+
};
84+
7485
parentForm.$addControl(form);
7586

7687
/**
@@ -125,6 +136,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
125136
if (control.$name) {
126137
form[control.$name] = control;
127138
}
139+
control.$$setParentForm(form);
128140
};
129141

130142
// Private API: rename a form control
@@ -159,6 +171,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
159171
});
160172

161173
arrayRemove(controls, control);
174+
control.$$setParentForm(nullFormCtrl);
162175
};
163176

164177

src/ng/directive/input.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,6 +1726,14 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
17261726
}
17271727
};
17281728

1729+
this.$$setParentForm = function(form) {
1730+
parentForm = form;
1731+
};
1732+
1733+
this.$$getParentForm = function(form) {
1734+
return parentForm;
1735+
};
1736+
17291737
/**
17301738
* @ngdoc method
17311739
* @name ngModel.NgModelController#$render
@@ -1800,7 +1808,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
18001808
unset: function(object, property) {
18011809
delete object[property];
18021810
},
1803-
parentForm: parentForm,
18041811
$animate: $animate
18051812
});
18061813

@@ -2411,12 +2418,12 @@ var ngModelDirective = function() {
24112418

24122419
attr.$observe('name', function(newValue) {
24132420
if (modelCtrl.$name !== newValue) {
2414-
formCtrl.$$renameControl(modelCtrl, newValue);
2421+
modelCtrl.$$getParentForm().$$renameControl(modelCtrl, newValue);
24152422
}
24162423
});
24172424

24182425
scope.$on('$destroy', function() {
2419-
formCtrl.$removeControl(modelCtrl);
2426+
modelCtrl.$$getParentForm().$removeControl(modelCtrl);
24202427
});
24212428
},
24222429
post: function ngModelPostLink(scope, element, attr, ctrls) {
@@ -2987,7 +2994,6 @@ function addSetValidityMethod(context) {
29872994
classCache = {},
29882995
set = context.set,
29892996
unset = context.unset,
2990-
parentForm = context.parentForm,
29912997
$animate = context.$animate;
29922998

29932999
classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
@@ -3038,7 +3044,7 @@ function addSetValidityMethod(context) {
30383044
combinedState = null;
30393045
}
30403046
toggleValidationCss(validationErrorKey, combinedState);
3041-
parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
3047+
ctrl.$$getParentForm().$setValidity(validationErrorKey, combinedState, ctrl);
30423048
}
30433049

30443050
function createAndSet(name, value, options) {

test/ng/directive/formSpec.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,50 @@ describe('form', function() {
5858
expect(form.alias).toBeUndefined();
5959
});
6060

61+
it('should not be affected by input controls that were removed from the form', function() {
62+
doc = $compile(
63+
'<form name="myForm">' +
64+
'<input ng-if="inputExists" name="alias" ng-model="value" store-model-ctrl/>' +
65+
'</form>')(scope);
66+
67+
scope.$apply('inputExists = true');
68+
control.$setValidity('required', false);
69+
scope.$apply('inputExists = false');
70+
71+
var form = scope.myForm;
72+
expect(form.$error.required).toBeFalsy();
73+
});
74+
75+
it('should not be affected by form controls that were removed from the form', function() {
76+
doc = $compile(
77+
'<form name="myForm">' +
78+
'<div ng-form="nestedForm" ng-if="formExists">' +
79+
'<input type="text" name="alias" ng-model="value" store-model-ctrl/>' +
80+
'</div>' +
81+
'</form>')(scope);
82+
83+
scope.$apply('formExists = true');
84+
control.$setValidity('required', false);
85+
scope.$apply('formExists = false');
86+
87+
var form = scope.myForm;
88+
expect(form.$error.required).toBeFalsy();
89+
});
90+
91+
it('should be affected by input controls that were re-added to the form', function() {
92+
doc = $compile(
93+
'<form name="myForm">' +
94+
'<input ng-if="inputExists" name="alias" ng-model="value" store-model-ctrl/>' +
95+
'</form>')(scope);
96+
97+
scope.$apply('inputExists = true');
98+
scope.$apply('inputExists = false');
99+
scope.$apply('inputExists = true');
100+
control.$setValidity('required', false);
101+
102+
var form = scope.myForm;
103+
expect(form.$error.required).toEqual([control]);
104+
});
61105

62106
it('should use ngForm value as form name', function() {
63107
doc = $compile(

0 commit comments

Comments
 (0)