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

Commit 6cc36f2

Browse files
committed
feat(ngModel) Allow running the formatters without a change to the modelValue
Fixes #3407
1 parent 9f7c5ce commit 6cc36f2

File tree

2 files changed

+72
-15
lines changed

2 files changed

+72
-15
lines changed

src/ng/directive/ngModel.js

+36-15
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,41 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
799799
}
800800
};
801801

802+
function formatValue(modelValue) {
803+
var formatters = ctrl.$formatters,
804+
idx = formatters.length;
805+
806+
var viewValue = modelValue;
807+
while (idx--) {
808+
viewValue = formatters[idx](viewValue);
809+
}
810+
811+
return viewValue;
812+
}
813+
814+
/**
815+
* @ngdoc method
816+
* @name ngModel.NgModelController#$setModelValue
817+
*
818+
*/
819+
this.$setModelValue = function(modelValue, fromModel) {
820+
var previousModelValue = ctrl.$modelValue;
821+
ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
822+
823+
if (!fromModel && previousModelValue !== ctrl.$modelValue) {
824+
this.$$writeModelToScope();
825+
}
826+
827+
var viewValue = formatValue(this.$modelValue);
828+
829+
if (this.$viewValue !== viewValue) {
830+
this.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
831+
this.$render();
832+
833+
ctrl.$$runValidators(undefined, modelValue, ctrl.$viewValue, noop);
834+
}
835+
};
836+
802837
// model -> value
803838
// Note: we cannot use a normal scope.$watch as we want to detect the following:
804839
// 1. scope value is 'a'
@@ -813,21 +848,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
813848
// if scope model value and ngModel value are out of sync
814849
// TODO(perf): why not move this to the action fn?
815850
if (modelValue !== ctrl.$modelValue) {
816-
ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
817-
818-
var formatters = ctrl.$formatters,
819-
idx = formatters.length;
820-
821-
var viewValue = modelValue;
822-
while (idx--) {
823-
viewValue = formatters[idx](viewValue);
824-
}
825-
if (ctrl.$viewValue !== viewValue) {
826-
ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
827-
ctrl.$render();
828-
829-
ctrl.$$runValidators(undefined, modelValue, viewValue, noop);
830-
}
851+
ctrl.$setModelValue(modelValue, true);
831852
}
832853

833854
return modelValue;

test/ng/directive/ngModelSpec.js

+36
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,42 @@ describe('ngModel', function() {
455455
});
456456

457457

458+
describe('$setModelValue', function() {
459+
460+
it('should set the value to $modelValue', function() {
461+
ctrl.$setModelValue(10);
462+
expect(ctrl.$modelValue).toBe(10);
463+
});
464+
465+
it('should update the value on the scope', inject(function($compile) {
466+
var element = $compile('<form name="form"><input name="field" ng-model="val" /></form>')(scope);
467+
468+
var input = element.children().eq(0);
469+
ctrl = input.controller('ngModel');
470+
471+
scope.val = 11;
472+
scope.$digest();
473+
ctrl.$setModelValue(22);
474+
scope.$digest();
475+
expect(scope.val).toBe(22);
476+
477+
dealoc(element);
478+
}));
479+
480+
it('should $render only if value changed', function() {
481+
spyOn(ctrl, '$render');
482+
483+
ctrl.$setModelValue(3);
484+
expect(ctrl.$render).toHaveBeenCalledOnce();
485+
ctrl.$render.reset();
486+
487+
ctrl.$formatters.push(function() {return 3;});
488+
ctrl.$setModelValue(5);
489+
expect(ctrl.$render).not.toHaveBeenCalled();
490+
});
491+
});
492+
493+
458494
describe('model -> view', function() {
459495

460496
it('should set the value to $modelValue', function() {

0 commit comments

Comments
 (0)