diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 639afcb9dfcb..9bd9767d1dae 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -2122,13 +2122,18 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ function writeToModelIfNeeded() { if (ctrl.$modelValue !== prevModelValue) { - ctrl.$$writeModelToScope(); + ctrl.$$writeModelToScope(prevModelValue); } } }; - this.$$writeModelToScope = function() { + this.$$writeModelToScope = function(oldVal) { ngModelSet(ctrl.$modelValue); + // String input types can transform a value into a string without touching it. + if (oldVal != null && !isNaN(oldVal) && + ctrl.$modelValue === oldVal.toString()) { + return; + } forEach(ctrl.$viewChangeListeners, function(listener) { try { listener(); diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 8d4e47763609..da8606ed54b3 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -1349,6 +1349,18 @@ describe('input', function() { }); + it('should not invoke viewChangeListeners before input is touched', function() { + scope.value = 1; + var change = scope.change = jasmine.createSpy('change'); + var element = $compile('
' + + '' + + '
')(scope); + scope.$digest(); + expect(change).not.toHaveBeenCalled(); + dealoc(element); + }); + + describe('compositionevents', function() { it('should not update the model between "compositionstart" and "compositionend" on non android', inject(function($sniffer) { $sniffer.android = false;