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

Commit c90cefe

Browse files
committed
feat(input): support constant expressions for ngTrueValue/ngFalseValue
ngTrueValue and ngFalseValue now support parsed expressions which the parser determines to be constant values. BREAKING CHANGE: Previously, these attributes would always be treated as strings. However, they are now parsed as expressions, and will throw if an expression is non-constant. To convert non-constant strings into constant expressions, simply wrap them in an extra pair of quotes, like so: <input type="checkbox" ng-model="..." ng-true-value="'truthyValue'"> Closes #8041 Closes #5346 Closes #1199
1 parent 8121449 commit c90cefe

File tree

3 files changed

+66
-13
lines changed

3 files changed

+66
-13
lines changed
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
@ngdoc error
2+
@name ngModel:constexpr
3+
@fullName Non-Constant Expression
4+
@description
5+
6+
Some attributes used in conjunction with ngModel (such as ngTrueValue or ngFalseValue) will only
7+
accept constant expressions.
8+
9+
Examples using constant expressions include:
10+
11+
```
12+
<input type="checkbox" ng-model="..." ng-true-value="'truthyValue'">
13+
<input type="checkbox" ng-model="..." ng-false-value="0">
14+
```
15+
16+
Examples of non-constant expressions include:
17+
18+
```
19+
<input type="checkbox" ng-model="..." ng-true-value="someValue">
20+
<input type="checkbox" ng-model="..." ng-false-value="{foo: someScopeValue}">
21+
```

src/ng/directive/input.js

+22-11
Original file line numberDiff line numberDiff line change
@@ -807,8 +807,8 @@ var inputType = {
807807
*
808808
* @param {string} ngModel Assignable angular expression to data-bind to.
809809
* @param {string=} name Property name of the form under which the control is published.
810-
* @param {string=} ngTrueValue The value to which the expression should be set when selected.
811-
* @param {string=} ngFalseValue The value to which the expression should be set when not selected.
810+
* @param {expression=} ngTrueValue The value to which the expression should be set when selected.
811+
* @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
812812
* @param {string=} ngChange Angular expression to be executed when input changes due to user
813813
* interaction with the input element.
814814
*
@@ -824,7 +824,7 @@ var inputType = {
824824
<form name="myForm" ng-controller="Ctrl">
825825
Value1: <input type="checkbox" ng-model="value1"> <br/>
826826
Value2: <input type="checkbox" ng-model="value2"
827-
ng-true-value="YES" ng-false-value="NO"> <br/>
827+
ng-true-value="'YES'" ng-false-value="'NO'"> <br/>
828828
<tt>value1 = {{value1}}</tt><br/>
829829
<tt>value2 = {{value2}}</tt><br/>
830830
</form>
@@ -1183,12 +1183,22 @@ function radioInputType(scope, element, attr, ctrl) {
11831183
attr.$observe('value', ctrl.$render);
11841184
}
11851185

1186-
function checkboxInputType(scope, element, attr, ctrl) {
1187-
var trueValue = attr.ngTrueValue,
1188-
falseValue = attr.ngFalseValue;
1186+
function parseConstantExpr($parse, context, name, expression, fallback) {
1187+
var parseFn;
1188+
if (isDefined(expression)) {
1189+
parseFn = $parse(expression);
1190+
if (!parseFn.constant) {
1191+
throw new minErr('ngModel')('constexpr', 'Expected constant expression for `{0}`, but saw ' +
1192+
'`{1}`.', name, expression);
1193+
}
1194+
return parseFn(context);
1195+
}
1196+
return fallback;
1197+
}
11891198

1190-
if (!isString(trueValue)) trueValue = true;
1191-
if (!isString(falseValue)) falseValue = false;
1199+
function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
1200+
var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
1201+
var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
11921202

11931203
var listener = function(ev) {
11941204
scope.$apply(function() {
@@ -1208,7 +1218,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
12081218
};
12091219

12101220
ctrl.$formatters.push(function(value) {
1211-
return value === trueValue;
1221+
return equals(value, trueValue);
12121222
});
12131223

12141224
ctrl.$parsers.push(function(value) {
@@ -1356,14 +1366,15 @@ function checkboxInputType(scope, element, attr, ctrl) {
13561366
</file>
13571367
</example>
13581368
*/
1359-
var inputDirective = ['$browser', '$sniffer', '$filter', function($browser, $sniffer, $filter) {
1369+
var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
1370+
function($browser, $sniffer, $filter, $parse) {
13601371
return {
13611372
restrict: 'E',
13621373
require: ['?ngModel'],
13631374
link: function(scope, element, attr, ctrls) {
13641375
if (ctrls[0]) {
13651376
(inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
1366-
$browser, $filter);
1377+
$browser, $filter, $parse);
13671378
}
13681379
}
13691380
};

test/ng/directive/inputSpec.js

+23-2
Original file line numberDiff line numberDiff line change
@@ -2528,8 +2528,8 @@ describe('input', function() {
25282528

25292529

25302530
it('should allow custom enumeration', function() {
2531-
compileInput('<input type="checkbox" ng-model="name" ng-true-value="y" ' +
2532-
'ng-false-value="n">');
2531+
compileInput('<input type="checkbox" ng-model="name" ng-true-value="\'y\'" ' +
2532+
'ng-false-value="\'n\'">');
25332533

25342534
scope.$apply(function() {
25352535
scope.name = 'y';
@@ -2554,6 +2554,27 @@ describe('input', function() {
25542554
});
25552555

25562556

2557+
it('should throw if ngTrueValue is present and not a constant expression', function() {
2558+
expect(function() {
2559+
compileInput('<input type="checkbox" ng-model="value" ng-true-value="yes" />');
2560+
}).toThrowMinErr('ngModel', 'constexpr', "Expected constant expression for `ngTrueValue`, but saw `yes`.");
2561+
});
2562+
2563+
2564+
it('should throw if ngFalseValue is present and not a constant expression', function() {
2565+
expect(function() {
2566+
compileInput('<input type="checkbox" ng-model="value" ng-false-value="no" />');
2567+
}).toThrowMinErr('ngModel', 'constexpr', "Expected constant expression for `ngFalseValue`, but saw `no`.");
2568+
});
2569+
2570+
2571+
it('should not throw if ngTrueValue or ngFalseValue are not present', function() {
2572+
expect(function() {
2573+
compileInput('<input type="checkbox" ng-model="value" />');
2574+
}).not.toThrow();
2575+
});
2576+
2577+
25572578
it('should be required if false', function() {
25582579
compileInput('<input type="checkbox" ng:model="value" required />');
25592580

0 commit comments

Comments
 (0)