Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

fix(ngModelOptions): do not trigger digest during debounce #8911

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 11 additions & 19 deletions src/ng/directive/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
};

Expand Down Expand Up @@ -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);
}
};

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 = {};
Expand Down Expand Up @@ -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();
});
}
};

Expand Down Expand Up @@ -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);
});
}

Expand Down
16 changes: 16 additions & 0 deletions test/ng/directive/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,22 @@ describe('input', function() {

}));

it('should not trigger digest while debouncing', inject(function($timeout) {
compileInput(
'<input type="text" ng-model="name" name="alias" '+
'ng-model-options="{ debounce: 10000 }"'+
'/>');

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(
Expand Down