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

Commit e6afca0

Browse files
m-amrNarretz
authored andcommitted
fix(ngValue): set the element's value property in addition to the value attribute
Input elements use the value attribute as their default value if the value property is not set. Once the value property has been set (by adding input), it will not react to changes to the value attribute anymore. Setting both attribute and property fixes this behavior, and makes it possible to use ngValue as a one-way bind. Closes #14031 Closes #13984 POSSIBLE BREAKING CHANGE: `ngValue` now also sets the value *property* of its element. Previously, it would only set the value *attribute*. This allows `ngValue` to be used as a one-way binding mechanism on `input[text]` and `textarea` elements without `ngModel`. Previously, these input types would not update correctly when only the value attribute was changed. This change should not affect any applications, as `ngValue` is mainly used on `input[radio]` and `option` elements, both of which are unaffected by this change.
1 parent c7010be commit e6afca0

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

src/ng/directive/input.js

+18-4
Original file line numberDiff line numberDiff line change
@@ -1970,9 +1970,12 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
19701970
* Likewise, `ngValue` can be used to set the value of `<option>` elements for
19711971
* the {@link select `select`} element.
19721972
*
1973+
* It can further be used to achieve one-way binding of a given expression to an input element that
1974+
* does not use ngModel.
1975+
*
19731976
* @element input
19741977
* @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
1975-
* of the `input` element
1978+
* and `value` property of the element
19761979
*
19771980
* @example
19781981
<example name="ngValue-directive" module="valueExample">
@@ -2011,22 +2014,33 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
20112014
</example>
20122015
*/
20132016
var ngValueDirective = function() {
2017+
/**
2018+
* inputs use the value attribute as their default value if the value property is not set.
2019+
* Once the value property has been set (by adding input), it will not react to changes to
2020+
* the value attribute anymore. Setting both attribute and property fixes this behavior, and
2021+
* makes it possible to use ngValue as a sort of one-way bind.
2022+
*/
2023+
function updateElementValue(element, attr, value) {
2024+
element.prop('value', value);
2025+
attr.$set('value', value);
2026+
}
2027+
20142028
return {
20152029
restrict: 'A',
20162030
priority: 100,
20172031
compile: function(tpl, tplAttr) {
20182032
if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
20192033
return function ngValueConstantLink(scope, elm, attr) {
2020-
attr.$set('value', scope.$eval(attr.ngValue));
2034+
var value = scope.$eval(attr.ngValue);
2035+
updateElementValue(elm, attr, value);
20212036
};
20222037
} else {
20232038
return function ngValueLink(scope, elm, attr) {
20242039
scope.$watch(attr.ngValue, function valueWatchAction(value) {
2025-
attr.$set('value', value);
2040+
updateElementValue(elm, attr, value);
20262041
});
20272042
};
20282043
}
20292044
}
20302045
};
20312046
};
2032-

test/ng/directive/inputSpec.js

+16
Original file line numberDiff line numberDiff line change
@@ -3784,6 +3784,22 @@ describe('input', function() {
37843784
expect(inputElm[0].getAttribute('value')).toBe('something');
37853785
});
37863786

3787+
they('should update the $prop "value" property and attribute after the bound expression changes', {
3788+
input: '<input type="text" ng-value="value">',
3789+
textarea: '<textarea ng-value="value"></textarea>'
3790+
}, function(tmpl) {
3791+
var element = helper.compileInput(tmpl);
3792+
3793+
helper.changeInputValueTo('newValue');
3794+
expect(element[0].value).toBe('newValue');
3795+
expect(element[0].getAttribute('value')).toBeNull();
3796+
3797+
$rootScope.$apply(function() {
3798+
$rootScope.value = 'anotherValue';
3799+
});
3800+
expect(element[0].value).toBe('anotherValue');
3801+
expect(element[0].getAttribute('value')).toBe('anotherValue');
3802+
});
37873803

37883804
it('should evaluate and set constant expressions', function() {
37893805
var inputElm = helper.compileInput('<input type="radio" ng-model="selected" ng-value="true">' +

0 commit comments

Comments
 (0)