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

fix(ngValue): set value property instead of attr #14031

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions src/ng/directive/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -1701,6 +1701,10 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
* so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
* the bound value.
*
* It can be used to achieve one-way binding of a given expression to the value of `element`,
* so that when the expression change the element is set to the bound value.
*
*
* `ngValue` is useful when dynamically generating lists of radio buttons using
* {@link ngRepeat `ngRepeat`}, as shown below.
*
Expand All @@ -1711,7 +1715,7 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
*
* @element input
* @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
* of the `input` element
* and `value` property of the element
*
* @example
<example name="ngValue-directive" module="valueExample">
Expand Down Expand Up @@ -1750,24 +1754,33 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
</example>
*/
var ngValueDirective = function() {
//helper function
var updateElementValue = function(element, attr, value) {
/**
* input use 'value attribute' as default value if 'value property has no value'
* but once set the 'value property' it will not read value from 'value attribute'
* so we set both the value attribute and property here to avoid this problem.
*/
attr.$set('value', value);
element.prop('value', value);
};

return {
restrict: 'A',
priority: 100,
compile: function(tpl, tplAttr) {
if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
return function ngValueConstantLink(scope, elm, attr) {
attr.$set('value', scope.$eval(attr.ngValue));
var value = scope.$eval(attr.ngValue);
updateElementValue(elm, attr, value);
};
} else {
return function ngValueLink(scope, elm, attr) {
scope.$watch(attr.ngValue, function valueWatchAction(value) {
attr.$set('value', value);
updateElementValue(elm, attr, value);
});
};
}
}
};
};



16 changes: 16 additions & 0 deletions test/ng/directive/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3046,6 +3046,22 @@ describe('input', function() {
expect(inputElm[0].getAttribute('value')).toBe('something');
});

they('should update the $prop "value" property and attribute after change the "value" property', {
input: '<input type="text" ng-value="value">',
textarea: '<textarea ng-value="value"></textarea>'
}, function(tmpl) {
var element = helper.compileInput(tmpl);

helper.changeInputValueTo('newValue');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no expect after his change, so either it's redundant or an expect is missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not 'redundant' it important to test that the
"input binding to the model" is still working after user edited the input, without it we are not testing the Issue
if "value property" has no value, it will read the value from "value attribute"
The Issue happened when user type something in the input,
see the following step

  1. User edit the input
    2 . then change the model value programmatically by changing the scope.
  2. The input is not updated will the new value of the model

I am trying to simulating what happen in the Issue #13984

do i need to add expect after it ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you should add an expect. Otherwise you can't be sure that the input / scope has really been changed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m-amr, basically this is redundant in this test, because we have already tested that the value property does have a value. If you wanted to test the scenario your describe, you should edit the input, before setting the value (maybe in a separate test).

FWIW, I don't think an extra expect is needed.

expect(element[0].value).toBe('newValue');
expect(element[0].getAttribute('value')).toBeNull();

$rootScope.$apply(function() {
$rootScope.value = 'anotherValue';
});
expect(element[0].value).toBe('anotherValue');
expect(element[0].getAttribute('value')).toBe('anotherValue');
});

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