@@ -95,6 +95,82 @@ describe('form', function() {
9595 } ) ;
9696
9797
98+ it ( 'should react to validation changes in manually added controls' , function ( ) {
99+ doc = $compile (
100+ '<form name="myForm">' +
101+ '<input name="control" ng-maxlength="1" ng-model="value" store-model-ctrl/>' +
102+ '</form>' ) ( scope ) ;
103+
104+ scope . $digest ( ) ;
105+
106+ var form = scope . myForm ;
107+
108+ var input = doc . find ( 'input' ) . eq ( 0 ) ;
109+
110+ // remove control and invalidate it
111+ form . $removeControl ( control ) ;
112+ expect ( form . control ) . toBeUndefined ( ) ;
113+
114+ changeInputValue ( input , 'abc' ) ;
115+ expect ( control . $error . maxlength ) . toBe ( true ) ;
116+ expect ( control . $dirty ) . toBe ( true ) ;
117+ expect ( form . $error . maxlength ) . toBeFalsy ( ) ;
118+ expect ( form . $dirty ) . toBe ( false ) ;
119+
120+ // re-add the control; its current validation state is not propagated
121+ form . $addControl ( control ) ;
122+ expect ( form . control ) . toBe ( control ) ;
123+ expect ( form . $error . maxlength ) . toBeFalsy ( ) ;
124+ expect ( form . $dirty ) . toBe ( false ) ;
125+
126+ // Only when the input changes again its validation state is propagated
127+ changeInputValue ( input , 'abcd' ) ;
128+ expect ( form . $error . maxlength [ 0 ] ) . toBe ( control ) ;
129+ expect ( form . $dirty ) . toBe ( false ) ;
130+ } ) ;
131+
132+
133+ it ( 'should use the correct parent when renaming and removing dynamically added controls' , function ( ) {
134+ scope . controlName = 'childControl' ;
135+ scope . hasChildControl = true ;
136+
137+ doc = $compile (
138+ '<form name="myForm">' +
139+ '<div ng-if="hasChildControl">' +
140+ '<input name="{{controlName}}" ng-maxlength="1" ng-model="value"/>' +
141+ '</div>' +
142+ '</form>' +
143+ '<form name="otherForm"></form>' ) ( scope ) ;
144+
145+ scope . $digest ( ) ;
146+
147+ var form = scope . myForm ;
148+ var otherForm = scope . otherForm ;
149+ var childControl = form . childControl ;
150+
151+ // remove child form and add it to another form
152+ form . $removeControl ( childControl ) ;
153+ otherForm . $addControl ( childControl ) ;
154+
155+ expect ( form . childControl ) . toBeUndefined ( ) ;
156+ expect ( otherForm . childControl ) . toBe ( childControl ) ;
157+
158+ // rename the childControl
159+ scope . controlName = 'childControlMoved' ;
160+ scope . $digest ( ) ;
161+
162+ expect ( form . childControlMoved ) . toBeUndefined ( ) ;
163+ expect ( otherForm . childControl ) . toBeUndefined ( ) ;
164+ expect ( otherForm . childControlMoved ) . toBe ( childControl ) ;
165+
166+ scope . hasChildControl = false ;
167+ scope . $digest ( ) ;
168+
169+ expect ( form . childControlMoved ) . toBeUndefined ( ) ;
170+ expect ( otherForm . childControlMoved ) . toBeUndefined ( ) ;
171+ } ) ;
172+
173+
98174 it ( 'should remove scope reference when form with no parent form is removed from the DOM' , function ( ) {
99175 var formController ;
100176 scope . ctrl = { } ;
@@ -614,6 +690,123 @@ describe('form', function() {
614690 expect ( child . $error . required ) . toEqual ( [ inputB ] ) ;
615691 } ) ;
616692
693+
694+ it ( 'should ignore changes in manually removed child forms' , function ( ) {
695+ doc = $compile (
696+ '<form name="myForm">' +
697+ '<ng-form name="childform">' +
698+ '<input name="childformcontrol" ng-maxlength="1" ng-model="value"/>' +
699+ '</ng-form>' +
700+ '</form>' ) ( scope ) ;
701+
702+ var form = scope . myForm ;
703+ var childformController = doc . find ( 'ng-form' ) . eq ( 0 ) . controller ( 'form' ) ;
704+
705+ var input = doc . find ( 'input' ) . eq ( 0 ) ;
706+ var inputController = input . controller ( 'ngModel' ) ;
707+
708+ changeInputValue ( input , 'ab' ) ;
709+ scope . $apply ( ) ;
710+
711+ expect ( form . $dirty ) . toBe ( true ) ;
712+ expect ( form . $error . maxlength ) . toBeTruthy ( ) ;
713+ expect ( form . $error . maxlength [ 0 ] . $name ) . toBe ( 'childform' ) ;
714+
715+ inputController . $setPristine ( ) ;
716+ expect ( form . $dirty ) . toBe ( true ) ;
717+
718+ form . $setPristine ( ) ;
719+
720+ // remove child form
721+ form . $removeControl ( childformController ) ;
722+ expect ( form . childform ) . toBeUndefined ( ) ;
723+ expect ( form . $error . maxlength ) . toBeFalsy ( ) ;
724+
725+ changeInputValue ( input , 'abc' ) ;
726+ scope . $apply ( ) ;
727+
728+ expect ( form . $error . maxlength ) . toBeFalsy ( ) ;
729+ expect ( form . $dirty ) . toBe ( false ) ;
730+ } ) ;
731+
732+
733+ it ( 'should react to changes in manually added child forms' , function ( ) {
734+ doc = $compile (
735+ '<form name="myForm">' +
736+ '<ng-form name="childForm">' +
737+ '<input name="childformcontrol" ng-maxlength="1" ng-model="value" />' +
738+ '</ng-form>' +
739+ '</form>' ) ( scope ) ;
740+
741+ var form = scope . myForm ;
742+ var childFormController = doc . find ( 'ng-form' ) . eq ( 0 ) . controller ( 'form' ) ;
743+
744+ var input = doc . find ( 'input' ) . eq ( 0 ) ;
745+
746+ // remove child form so we can add it manually
747+ form . $removeControl ( childFormController ) ;
748+ changeInputValue ( input , 'ab' ) ;
749+
750+ expect ( form . childForm ) . toBeUndefined ( ) ;
751+ expect ( form . $dirty ) . toBe ( false ) ;
752+ expect ( form . $error . maxlength ) . toBeFalsy ( ) ;
753+
754+ // re-add the child form; its current validation state is not propagated
755+ form . $addControl ( childFormController ) ;
756+ expect ( form . childForm ) . toBe ( childFormController ) ;
757+ expect ( form . $error . maxlength ) . toBeFalsy ( ) ;
758+ expect ( form . $dirty ) . toBe ( false ) ;
759+
760+ // Only when the input inside the child form changes, the validation state is propagated
761+ changeInputValue ( input , 'abc' ) ;
762+ expect ( form . $error . maxlength [ 0 ] ) . toBe ( childFormController ) ;
763+ expect ( form . $dirty ) . toBe ( false ) ;
764+ } ) ;
765+
766+
767+ it ( 'should use the correct parent when renaming and removing dynamically added forms' , function ( ) {
768+ scope . formName = 'childForm' ;
769+ scope . hasChildForm = true ;
770+
771+ doc = $compile (
772+ '<form name="myForm">' +
773+ '<div ng-if="hasChildForm">' +
774+ '<ng-form name="{{formName}}">' +
775+ '<input name="childformcontrol" ng-maxlength="1" ng-model="value"/>' +
776+ '</ng-form>' +
777+ '</div>' +
778+ '</form>' +
779+ '<form name="otherForm"></form>' ) ( scope ) ;
780+
781+ scope . $digest ( ) ;
782+
783+ var form = scope . myForm ;
784+ var otherForm = scope . otherForm ;
785+ var childForm = form . childForm ;
786+
787+ // remove child form and add it to another form
788+ form . $removeControl ( childForm ) ;
789+ otherForm . $addControl ( childForm ) ;
790+
791+ expect ( form . childForm ) . toBeUndefined ( ) ;
792+ expect ( otherForm . childForm ) . toBe ( childForm ) ;
793+
794+ // rename the childForm
795+ scope . formName = 'childFormMoved' ;
796+ scope . $digest ( ) ;
797+
798+ expect ( form . childFormMoved ) . toBeUndefined ( ) ;
799+ expect ( otherForm . childForm ) . toBeUndefined ( ) ;
800+ expect ( otherForm . childFormMoved ) . toBe ( childForm ) ;
801+
802+ scope . hasChildForm = false ;
803+ scope . $digest ( ) ;
804+
805+ expect ( form . childFormMoved ) . toBeUndefined ( ) ;
806+ expect ( otherForm . childFormMoved ) . toBeUndefined ( ) ;
807+ } ) ;
808+
809+
617810 it ( 'should chain nested forms in repeater' , function ( ) {
618811 doc = jqLite (
619812 '<ng:form name=parent>' +
0 commit comments