Skip to content

Commit da2bfb6

Browse files
committed
fix(form): fix(form): make ngForm $pristine after nested control.$setPristine() (brute force version)
When calling $setPristine on the nested form or control, form becomes $pristine of all the nested controls are pristine Closes angular#13715
1 parent 61ac267 commit da2bfb6

File tree

2 files changed

+101
-28
lines changed

2 files changed

+101
-28
lines changed

Diff for: src/ng/directive/form.js

+3-10
Original file line numberDiff line numberDiff line change
@@ -279,16 +279,9 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
279279

280280
// Private API: update form pristine-ness
281281
form.$$updatePristine = function() {
282-
var isPristine = true,
283-
controlsLength = controls.length,
284-
i;
285-
286-
for (i = 0; i < controlsLength; i++) {
287-
if (!controls[i].$pristine) {
288-
isPristine = false;
289-
break;
290-
}
291-
}
282+
var isPristine = controls.every(function(control) {
283+
return control.$pristine;
284+
});
292285

293286
if (isPristine) {
294287
// All the nested controls are already pristine.

Diff for: test/ng/directive/formSpec.js

+98-18
Original file line numberDiff line numberDiff line change
@@ -714,10 +714,7 @@ describe('form', function() {
714714
expect(form.$error.maxlength[0].$name).toBe('childform');
715715

716716
inputController.$setPristine();
717-
// this assertion prevents to propagate prestine to the parent form
718-
// expect(form.$dirty).toBe(true);
719-
720-
form.$setPristine();
717+
expect(form.$dirty).toBe(false);
721718

722719
// remove child form
723720
form.$removeControl(childformController);
@@ -1057,7 +1054,7 @@ describe('form', function() {
10571054

10581055
childFormCtrl.$setDirty();
10591056
scope.$apply();
1060-
expect(parentForm).not.toBePristine();
1057+
expect(parentForm).toBeDirty();
10611058

10621059
childFormCtrl.$setPristine();
10631060
scope.$apply();
@@ -1068,55 +1065,138 @@ describe('form', function() {
10681065
it('should be pristine if all the nested controls are pristine', function() {
10691066
doc = $compile(
10701067
'<form name="form">' +
1071-
'<input ng-model="inputModel1" name="input1">' +
1072-
'<input ng-model="inputModel2" name="input2">' +
1068+
'<div ng-form name="childForm">' +
1069+
'<input ng-model="inputModel1" name="input1">' +
1070+
'<input ng-model="inputModel2" name="input2">' +
1071+
'</div>' +
10731072
'</form>')(scope);
10741073

10751074
var form = doc,
1076-
formCtrl = scope.form,
1075+
childForm = form.find('div').eq(0),
10771076
input1 = form.find('input').eq(0),
10781077
input2 = form.find('input').eq(1),
10791078
inputCtrl1 = input1.controller('ngModel'),
10801079
inputCtrl2 = input2.controller('ngModel');
10811080

10821081
inputCtrl1.$setDirty();
1082+
inputCtrl1.$setDirty();
1083+
scope.$apply();
1084+
expect(form).toBeDirty();
1085+
expect(childForm).toBeDirty();
1086+
1087+
inputCtrl2.$setDirty();
10831088
inputCtrl2.$setDirty();
10841089
scope.$apply();
1085-
expect(form).not.toBePristine();
1090+
expect(form).toBeDirty();
1091+
expect(childForm).toBeDirty();
10861092

10871093
inputCtrl1.$setPristine();
10881094
scope.$apply();
1089-
expect(form).not.toBePristine();
1095+
expect(form).toBeDirty();
1096+
expect(childForm).toBeDirty();
10901097

10911098
inputCtrl2.$setPristine();
10921099
scope.$apply();
10931100
expect(form).toBePristine();
1101+
expect(childForm).toBePristine();
10941102
});
10951103

10961104
it('should be pristine if all the nested forms are pristine', function() {
10971105
doc = $compile(
1098-
'<form name="form">' +
1099-
'<div ng-form name="childForm1"></div>' +
1100-
'<div ng-form name="childForm2"></div>' +
1106+
'<form name="outerForm1">' +
1107+
'<div ng-form name="outerForm2">' +
1108+
'<div ng-form name="childForm1"></div>' +
1109+
'<div ng-form name="childForm2"></div>' +
1110+
'</div>' +
11011111
'</form>')(scope);
11021112

1103-
var form = doc,
1104-
formCtrl = scope.form,
1113+
var outerForm1 = doc,
1114+
outerForm2 = doc.find('div').eq(0),
11051115
childFormCtrl1 = scope.childForm1,
11061116
childFormCtrl2 = scope.childForm2;
11071117

11081118
childFormCtrl1.$setDirty();
1119+
scope.$apply();
1120+
expect(outerForm1).toBeDirty();
1121+
expect(outerForm2).toBeDirty();
11091122
childFormCtrl2.$setDirty();
11101123
scope.$apply();
1111-
expect(form).not.toBePristine();
1124+
expect(outerForm1).toBeDirty();
1125+
expect(outerForm2).toBeDirty();
11121126

11131127
childFormCtrl1.$setPristine();
11141128
scope.$apply();
1115-
expect(form).not.toBePristine();
1129+
expect(outerForm1).toBeDirty();
1130+
expect(outerForm2).toBeDirty();
11161131

11171132
childFormCtrl2.$setPristine();
11181133
scope.$apply();
1119-
expect(form).toBePristine();
1134+
expect(outerForm1).toBePristine();
1135+
expect(outerForm2).toBePristine();
1136+
});
1137+
1138+
it('should properly handle added/removed controls', function() {
1139+
1140+
var test = function(input, inputCtrl) {
1141+
doc = $compile(
1142+
'<form name="outerForm">' +
1143+
'<div ng-form name="innerForm"></div>' +
1144+
'</form>')(scope);
1145+
1146+
var outerForm = doc,
1147+
innerForm = doc.find('div').eq(0),
1148+
innerFormCtrl = innerForm.controller('form');
1149+
1150+
inputCtrl.$setDirty();
1151+
1152+
// just add control does not change form pristine-ness
1153+
innerFormCtrl.$addControl(inputCtrl);
1154+
scope.$apply();
1155+
expect(innerForm).toBePristine();
1156+
1157+
// change after adding
1158+
inputCtrl.$setDirty();
1159+
scope.$apply();
1160+
expect(innerForm).toBeDirty();
1161+
1162+
innerFormCtrl.$removeControl(inputCtrl);
1163+
1164+
// removed control does not affect
1165+
inputCtrl.$setPristine();
1166+
scope.$apply();
1167+
expect(innerForm).toBeDirty();
1168+
1169+
innerFormCtrl.$addControl(inputCtrl);
1170+
scope.$apply();
1171+
expect(innerForm).toBeDirty();
1172+
1173+
inputCtrl.$setPristine();
1174+
scope.$apply();
1175+
expect(innerForm).toBePristine();
1176+
1177+
innerFormCtrl.$removeControl(inputCtrl);
1178+
inputCtrl.$setPristine();
1179+
innerFormCtrl.$addControl(inputCtrl);
1180+
scope.$apply();
1181+
expect(innerForm).toBePristine();
1182+
1183+
inputCtrl.$setDirty();
1184+
scope.$apply();
1185+
expect(outerForm).toBeDirty();
1186+
};
1187+
1188+
var input1 = $compile('<input ng-model="inputModel" name="input">')(scope),
1189+
inputCtrl1 = input1.controller('ngModel'),
1190+
1191+
input2 = $compile('<div ng-form name="input"></div>')(scope),
1192+
inputCtrl2 = input2.controller('form');
1193+
1194+
// test for input
1195+
test(input1, inputCtrl1);
1196+
dealoc(doc);
1197+
1198+
// test for ng-form
1199+
test(input2, inputCtrl2);
11201200
});
11211201
});
11221202

0 commit comments

Comments
 (0)