Skip to content

Commit

Permalink
feat(ngModel) Allow running the formatters without a change to the mo…
Browse files Browse the repository at this point in the history
…delValue

Fixes angular#3407
  • Loading branch information
realityking committed Mar 5, 2015
1 parent 9f7c5ce commit 6cc36f2
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 15 deletions.
51 changes: 36 additions & 15 deletions src/ng/directive/ngModel.js
Expand Up @@ -799,6 +799,41 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
}
};

function formatValue(modelValue) {
var formatters = ctrl.$formatters,
idx = formatters.length;

var viewValue = modelValue;
while (idx--) {
viewValue = formatters[idx](viewValue);
}

return viewValue;
}

/**
* @ngdoc method
* @name ngModel.NgModelController#$setModelValue
*
*/
this.$setModelValue = function(modelValue, fromModel) {
var previousModelValue = ctrl.$modelValue;
ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;

if (!fromModel && previousModelValue !== ctrl.$modelValue) {
this.$$writeModelToScope();
}

var viewValue = formatValue(this.$modelValue);

if (this.$viewValue !== viewValue) {
this.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
this.$render();

ctrl.$$runValidators(undefined, modelValue, ctrl.$viewValue, noop);
}
};

// model -> value
// Note: we cannot use a normal scope.$watch as we want to detect the following:
// 1. scope value is 'a'
Expand All @@ -813,21 +848,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
// if scope model value and ngModel value are out of sync
// TODO(perf): why not move this to the action fn?
if (modelValue !== ctrl.$modelValue) {
ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;

var formatters = ctrl.$formatters,
idx = formatters.length;

var viewValue = modelValue;
while (idx--) {
viewValue = formatters[idx](viewValue);
}
if (ctrl.$viewValue !== viewValue) {
ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
ctrl.$render();

ctrl.$$runValidators(undefined, modelValue, viewValue, noop);
}
ctrl.$setModelValue(modelValue, true);
}

return modelValue;
Expand Down
36 changes: 36 additions & 0 deletions test/ng/directive/ngModelSpec.js
Expand Up @@ -455,6 +455,42 @@ describe('ngModel', function() {
});


describe('$setModelValue', function() {

it('should set the value to $modelValue', function() {
ctrl.$setModelValue(10);
expect(ctrl.$modelValue).toBe(10);
});

it('should update the value on the scope', inject(function($compile) {
var element = $compile('<form name="form"><input name="field" ng-model="val" /></form>')(scope);

var input = element.children().eq(0);
ctrl = input.controller('ngModel');

scope.val = 11;
scope.$digest();
ctrl.$setModelValue(22);
scope.$digest();
expect(scope.val).toBe(22);

dealoc(element);
}));

it('should $render only if value changed', function() {
spyOn(ctrl, '$render');

ctrl.$setModelValue(3);
expect(ctrl.$render).toHaveBeenCalledOnce();
ctrl.$render.reset();

ctrl.$formatters.push(function() {return 3;});
ctrl.$setModelValue(5);
expect(ctrl.$render).not.toHaveBeenCalled();
});
});


describe('model -> view', function() {

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

0 comments on commit 6cc36f2

Please sign in to comment.