diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 977be6c7bfa6..392286de0367 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -956,13 +956,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the // control's value is the same empty value twice in a row. if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) { - if (scope.$root.$$phase) { - ctrl.$setViewValue(value, event); - } else { - scope.$apply(function() { - ctrl.$setViewValue(value, event); - }); - } + ctrl.$setViewValue(value, event); } }; @@ -1173,9 +1167,7 @@ function radioInputType(scope, element, attr, ctrl) { var listener = function(ev) { if (element[0].checked) { - scope.$apply(function() { - ctrl.$setViewValue(attr.value, ev && ev.type); - }); + ctrl.$setViewValue(attr.value, ev && ev.type); } }; @@ -1207,9 +1199,7 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false); var listener = function(ev) { - scope.$apply(function() { - ctrl.$setViewValue(element[0].checked, ev && ev.type); - }); + ctrl.$setViewValue(element[0].checked, ev && ev.type); }; element.on('click', listener); @@ -1588,8 +1578,8 @@ var VALID_CLASS = 'ng-valid', * * */ -var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', - function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout) { +var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', + function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope) { this.$viewValue = Number.NaN; this.$modelValue = Number.NaN; this.$validators = {}; @@ -2112,8 +2102,12 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ pendingDebounce = $timeout(function() { ctrl.$commitViewValue(); }, debounceDelay); - } else { + } else if ($rootScope.$$phase) { ctrl.$commitViewValue(); + } else { + $scope.$apply(function() { + ctrl.$commitViewValue(); + }); } }; @@ -2330,9 +2324,7 @@ var ngModelDirective = function() { var modelCtrl = ctrls[0]; if (modelCtrl.$options && modelCtrl.$options.updateOn) { element.on(modelCtrl.$options.updateOn, function(ev) { - scope.$apply(function() { - modelCtrl.$$debounceViewValueCommit(ev && ev.type); - }); + modelCtrl.$$debounceViewValueCommit(ev && ev.type); }); } diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 3c5e6d437cb1..ed9bef89f86a 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -1414,6 +1414,22 @@ describe('input', function() { })); + it('should not trigger digest while debouncing', inject(function($timeout) { + compileInput( + ''); + + var watchSpy = jasmine.createSpy('watchSpy'); + scope.$watch(watchSpy); + + changeInputValueTo('a'); + expect(watchSpy).not.toHaveBeenCalled(); + + $timeout.flush(10000); + expect(watchSpy).toHaveBeenCalled(); + })); + it('should allow selecting different debounce timeouts for each event', inject(function($timeout) { compileInput(