Skip to content

Commit 3392351

Browse files
committed
fix(ngModel): execute getter/setter models with context
1 parent e69c180 commit 3392351

File tree

2 files changed

+16
-27
lines changed

2 files changed

+16
-27
lines changed

src/ng/directive/input.js

+13-24
Original file line numberDiff line numberDiff line change
@@ -1715,33 +1715,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
17151715
this.$name = $interpolate($attr.name || '', false)($scope);
17161716

17171717

1718-
var parsedNgModel = $parse($attr.ngModel),
1719-
pendingDebounce = null,
1718+
var pendingDebounce = null,
17201719
ctrl = this;
17211720

1722-
var ngModelGet = function ngModelGet() {
1723-
var modelValue = parsedNgModel($scope);
1724-
if (ctrl.$options && ctrl.$options.getterSetter && isFunction(modelValue)) {
1725-
modelValue = modelValue();
1726-
}
1727-
return modelValue;
1728-
};
1729-
1730-
var ngModelSet = function ngModelSet(newValue) {
1731-
var getterSetter;
1732-
if (ctrl.$options && ctrl.$options.getterSetter &&
1733-
isFunction(getterSetter = parsedNgModel($scope))) {
1734-
1735-
getterSetter(ctrl.$modelValue);
1736-
} else {
1737-
parsedNgModel.assign($scope, ctrl.$modelValue);
1738-
}
1739-
};
1721+
var ngModelGet = $parse($attr.ngModel);
1722+
var ngModelSet = ngModelGet.assign;
17401723

17411724
this.$$setOptions = function(options) {
17421725
ctrl.$options = options;
17431726

1744-
if (!parsedNgModel.assign && (!options || !options.getterSetter)) {
1727+
if (options && options.getterSetter) {
1728+
ngModelGet = $parse($attr.ngModel + "()");
1729+
var ngModelSetInvoke = $parse($attr.ngModel + "($$ngModelValue)");
1730+
ngModelSet = function($scope, value) {
1731+
ngModelSetInvoke($scope, {$$ngModelValue: value});
1732+
};
1733+
} else if (!ngModelSet) {
17451734
throw $ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
17461735
$attr.ngModel, startingTag($element));
17471736
}
@@ -2103,7 +2092,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
21032092
}
21042093
if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
21052094
// ctrl.$modelValue has not been touched yet...
2106-
ctrl.$modelValue = ngModelGet();
2095+
ctrl.$modelValue = ngModelGet($scope);
21072096
}
21082097
var prevModelValue = ctrl.$modelValue;
21092098
var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
@@ -2130,7 +2119,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
21302119
};
21312120

21322121
this.$$writeModelToScope = function() {
2133-
ngModelSet(ctrl.$modelValue);
2122+
ngModelSet($scope, ctrl.$modelValue);
21342123
forEach(ctrl.$viewChangeListeners, function(listener) {
21352124
try {
21362125
listener();
@@ -2226,7 +2215,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
22262215
// ng-change executes in apply phase
22272216
// 4. view should be changed back to 'a'
22282217
$scope.$watch(function ngModelWatch() {
2229-
var modelValue = ngModelGet();
2218+
var modelValue = ngModelGet($scope);
22302219

22312220
// if scope model value and ngModel value are out of sync
22322221
// TODO(perf): why not move this to the action fn?

test/ng/directive/inputSpec.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1957,10 +1957,10 @@ describe('input', function() {
19571957
expect(spy).toHaveBeenCalledWith('a');
19581958
expect(scope.name).toBe(spy);
19591959

1960-
scope.name = 'c';
1960+
scope.name = null;
19611961
changeInputValueTo('d');
1962-
expect(inputElm.val()).toBe('d');
1963-
expect(scope.name).toBe('d');
1962+
expect(inputElm.val()).toBe('');
1963+
expect(scope.name).toBe(null);
19641964
});
19651965

19661966
it('should fail on non-assignable model binding if getterSetter is false', function() {

0 commit comments

Comments
 (0)