diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index abc689193ee7..f0e8170f6f8a 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1709,7 +1709,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ $animate.removeClass($element, PENDING_CLASS); }; - this.$$setPending = function(validationErrorKey, promise, currentValue) { + this.$$setPending = function(validationErrorKey, promise, modelValue) { ctrl.$pending = ctrl.$pending || {}; if (angular.isUndefined(ctrl.$pending[validationErrorKey])) { ctrl.$pending[validationErrorKey] = true; @@ -1725,7 +1725,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ //Special-case for (undefined|null|false|NaN) values to avoid //having to compare each of them with each other - currentValue = currentValue || ''; + var currentValue = ctrl.$viewValue || ''; promise.then(resolve(true), resolve(false)); function resolve(bool) { @@ -1737,7 +1737,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ ctrl.$setValidity(validationErrorKey, bool); if (pendingCount === 0) { ctrl.$$clearPending(); - ctrl.$$updateValidModelValue(value); + ctrl.$$updateValidModelValue(modelValue); ctrl.$$writeModelToScope(); } } @@ -1924,14 +1924,14 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ } var prev = ctrl.$modelValue; - ctrl.$$runValidators(ctrl.$$invalidModelValue || ctrl.$modelValue, ctrl.$viewValue); + ctrl.$$runValidators(ctrl.$$invalidModelValue || ctrl.$modelValue); if (prev !== ctrl.$modelValue) { ctrl.$$writeModelToScope(); } }; - this.$$runValidators = function(modelValue, viewValue) { - // this is called in the event if incase the input value changes + this.$$runValidators = function(modelValue) { + // this is called in the event if in case the input value changes // while a former asynchronous validator is still doing its thing if (ctrl.$pending) { ctrl.$$clearPending(); @@ -1956,7 +1956,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ function validate(validators, callback) { var status = true; forEach(validators, function(fn, name) { - var result = fn(modelValue, viewValue); + var result = fn(modelValue, ctrl.$viewValue); callback(name, result); status = status && result; }); @@ -2016,7 +2016,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ } else if (ctrl.$modelValue !== modelValue && (isUndefined(ctrl.$$invalidModelValue) || ctrl.$$invalidModelValue != modelValue)) { ctrl.$setValidity(parserName, true); - ctrl.$$runValidators(modelValue, viewValue); + ctrl.$$runValidators(modelValue); ctrl.$$writeModelToScope(); } }; @@ -2133,10 +2133,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ viewValue = formatters[idx](viewValue); } - ctrl.$$runValidators(modelValue, viewValue); - if (ctrl.$viewValue !== viewValue) { ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue; + ctrl.$$runValidators(modelValue); ctrl.$render(); } } diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 3c5e6d437cb1..b34badef2da7 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -516,6 +516,42 @@ describe('NgModelController', function() { expect(ctrl.$pending).toBeUndefined(); })); + it('should not run validators in case view value is not re-rendered', function() { + ctrl.$formatters.push(function(value) { + return 'nochange'; + }); + + ctrl.$validators.spyValidator = jasmine.createSpy('spyValidator'); + scope.$apply('value = "first"'); + scope.$apply('value = "second"'); + expect(ctrl.$validators.spyValidator).toHaveBeenCalledOnce(); + }); + + it('should render a validator asynchronously when parser is defined', inject(function($q) { + var defer; + ctrl.$asyncValidators.promiseValidator = function(value) { + defer = $q.defer(); + return defer.promise; + }; + ctrl.$parsers.push(function(value) { + return value + '-a'; + }); + + ctrl.$setViewValue(''); + + expect(ctrl.$valid).toBeUndefined(); + expect(ctrl.$invalid).toBeUndefined(); + expect(ctrl.$pending.promiseValidator).toBe(true); + + defer.resolve(); + scope.$digest(); + + expect(ctrl.$valid).toBe(true); + expect(ctrl.$invalid).toBe(false); + expect(ctrl.$pending).toBeUndefined(); + expect(ctrl.$modelValue).toBe('-a'); + })); + it('should throw an error when a promise is not returned for an asynchronous validator', inject(function($q) { ctrl.$asyncValidators.async = function(value) { return true;