diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 9bd6dc979ab6..8c2c220148e1 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -2416,7 +2416,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ * */ -var ngModelDirective = function() { +var ngModelDirective = ['$rootScope', function($rootScope) { return { restrict: 'A', require: ['ngModel', '^?form', '^?ngModelOptions'], @@ -2460,15 +2460,17 @@ var ngModelDirective = function() { element.on('blur', function(ev) { if (modelCtrl.$touched) return; - scope.$apply(function() { - modelCtrl.$setTouched(); - }); + if ($rootScope.$$phase) { + scope.$evalAsync(modelCtrl.$setTouched); + } else { + scope.$apply(modelCtrl.$setTouched); + } }); } }; } }; -}; +}]; /** diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 8d4e47763609..09e09e262964 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -1144,6 +1144,32 @@ describe('ngModel', function() { dealoc(element); })); + it('should digest asynchronously on "blur" event if a apply is already in progress', + inject(function($compile, $rootScope) { + + var element = $compile('
')($rootScope); + var inputElm = element.find('input'); + var control = $rootScope.myForm.myControl; + + $rootScope.$apply(function() { + expect(control.$touched).toBe(false); + expect(control.$untouched).toBe(true); + + browserTrigger(inputElm, 'blur'); + + expect(control.$touched).toBe(false); + expect(control.$untouched).toBe(true); + }); + + expect(control.$touched).toBe(true); + expect(control.$untouched).toBe(false); + + dealoc(element); + })); + + it('should register/deregister a nested ngModel with parent form when entering or leaving DOM', inject(function($compile, $rootScope) {