diff options
| author | Igor Minar | 2013-11-04 10:32:23 -0800 |
|---|---|---|
| committer | Igor Minar | 2013-11-04 10:35:51 -0800 |
| commit | 8f989d652f70fd147f66a18411070c7b939e242e (patch) | |
| tree | 5400ef23b01d7b3f90428fd595fc8ac3af0c8162 /test/ng/directive/inputSpec.js | |
| parent | 9483373c331343648e079420b3eb1f564d410ff2 (diff) | |
| download | angular.js-8f989d652f70fd147f66a18411070c7b939e242e.tar.bz2 | |
fix(ngModel): deregister from the form on scope not DOM destruction
Due to animations, DOM might get destroyed much later than scope and so the element $destroy event
might get fired outside of $digest, which causes changes to the validation model go unobserved
until the next digest. By deregistering on scope event, the deregistration always happens
in $digest and the form validation model changes will be observed.
Closes #4226
Closes #4779
Diffstat (limited to 'test/ng/directive/inputSpec.js')
| -rw-r--r-- | test/ng/directive/inputSpec.js | 89 |
1 files changed, 78 insertions, 11 deletions
diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index c60960f0..3783c9ed 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -305,6 +305,84 @@ describe('ngModel', function() { expect(element).toBeInvalid(); expect(element).toHaveClass('ng-invalid-required'); })); + + + it('should register/deregister a nested ngModel with parent form when entering or leaving DOM', + inject(function($compile, $rootScope) { + + var element = $compile('<form name="myForm">' + + '<input ng-if="inputPresent" name="myControl" ng-model="value" required >' + + '</form>')($rootScope); + var isFormValid; + + $rootScope.inputPresent = false; + $rootScope.$watch('myForm.$valid', function(value) { isFormValid = value; }); + + $rootScope.$apply(); + + expect($rootScope.myForm.$valid).toBe(true); + expect(isFormValid).toBe(true); + expect($rootScope.myForm.myControl).toBeUndefined(); + + $rootScope.inputPresent = true; + $rootScope.$apply(); + + expect($rootScope.myForm.$valid).toBe(false); + expect(isFormValid).toBe(false); + expect($rootScope.myForm.myControl).toBeDefined(); + + $rootScope.inputPresent = false; + $rootScope.$apply(); + + expect($rootScope.myForm.$valid).toBe(true); + expect(isFormValid).toBe(true); + expect($rootScope.myForm.myControl).toBeUndefined(); + + dealoc(element); + })); + + + it('should register/deregister a nested ngModel with parent form when entering or leaving DOM with animations', + function() { + + // ngAnimate performs the dom manipulation after digest, and since the form validity can be affected by a form + // control going away we must ensure that the deregistration happens during the digest while we are still doing + // dirty checking. + module('ngAnimate'); + + inject(function($compile, $rootScope) { + var element = $compile('<form name="myForm">' + + '<input ng-if="inputPresent" name="myControl" ng-model="value" required >' + + '</form>')($rootScope); + var isFormValid; + + $rootScope.inputPresent = false; + // this watch ensure that the form validity gets updated during digest (so that we can observe it) + $rootScope.$watch('myForm.$valid', function(value) { isFormValid = value; }); + + $rootScope.$apply(); + + expect($rootScope.myForm.$valid).toBe(true); + expect(isFormValid).toBe(true); + expect($rootScope.myForm.myControl).toBeUndefined(); + + $rootScope.inputPresent = true; + $rootScope.$apply(); + + expect($rootScope.myForm.$valid).toBe(false); + expect(isFormValid).toBe(false); + expect($rootScope.myForm.myControl).toBeDefined(); + + $rootScope.inputPresent = false; + $rootScope.$apply(); + + expect($rootScope.myForm.$valid).toBe(true); + expect(isFormValid).toBe(true); + expect($rootScope.myForm.myControl).toBeUndefined(); + + dealoc(element); + }); + }); }); @@ -369,17 +447,6 @@ describe('input', function() { }); - it('should cleanup it self from the parent form', function() { - compileInput('<input ng-model="name" name="alias" required>'); - - scope.$apply(); - expect(scope.form.$error.required.length).toBe(1); - - inputElm.remove(); - expect(scope.form.$error.required).toBe(false); - }); - - it('should update the model on "blur" event', function() { compileInput('<input type="text" ng-model="name" name="alias" ng-change="change()" />'); |
