mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-06-19 17:53:27 +08:00
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
This commit is contained in:
21
docs/content/error/ngModel/constexpr.ngdoc
Normal file
21
docs/content/error/ngModel/constexpr.ngdoc
Normal file
@@ -0,0 +1,21 @@
|
||||
@ngdoc error
|
||||
@name ngModel:constexpr
|
||||
@fullName Non-Constant Expression
|
||||
@description
|
||||
|
||||
Some attributes used in conjunction with ngModel (such as ngTrueValue or ngFalseValue) will only
|
||||
accept constant expressions.
|
||||
|
||||
Examples using constant expressions include:
|
||||
|
||||
```
|
||||
<input type="checkbox" ng-model="..." ng-true-value="'truthyValue'">
|
||||
<input type="checkbox" ng-model="..." ng-false-value="0">
|
||||
```
|
||||
|
||||
Examples of non-constant expressions include:
|
||||
|
||||
```
|
||||
<input type="checkbox" ng-model="..." ng-true-value="someValue">
|
||||
<input type="checkbox" ng-model="..." ng-false-value="{foo: someScopeValue}">
|
||||
```
|
||||
@@ -807,8 +807,8 @@ var inputType = {
|
||||
*
|
||||
* @param {string} ngModel Assignable angular expression to data-bind to.
|
||||
* @param {string=} name Property name of the form under which the control is published.
|
||||
* @param {string=} ngTrueValue The value to which the expression should be set when selected.
|
||||
* @param {string=} ngFalseValue The value to which the expression should be set when not selected.
|
||||
* @param {expression=} ngTrueValue The value to which the expression should be set when selected.
|
||||
* @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
|
||||
* @param {string=} ngChange Angular expression to be executed when input changes due to user
|
||||
* interaction with the input element.
|
||||
*
|
||||
@@ -824,7 +824,7 @@ var inputType = {
|
||||
<form name="myForm" ng-controller="Ctrl">
|
||||
Value1: <input type="checkbox" ng-model="value1"> <br/>
|
||||
Value2: <input type="checkbox" ng-model="value2"
|
||||
ng-true-value="YES" ng-false-value="NO"> <br/>
|
||||
ng-true-value="'YES'" ng-false-value="'NO'"> <br/>
|
||||
<tt>value1 = {{value1}}</tt><br/>
|
||||
<tt>value2 = {{value2}}</tt><br/>
|
||||
</form>
|
||||
@@ -1183,12 +1183,22 @@ function radioInputType(scope, element, attr, ctrl) {
|
||||
attr.$observe('value', ctrl.$render);
|
||||
}
|
||||
|
||||
function checkboxInputType(scope, element, attr, ctrl) {
|
||||
var trueValue = attr.ngTrueValue,
|
||||
falseValue = attr.ngFalseValue;
|
||||
function parseConstantExpr($parse, context, name, expression, fallback) {
|
||||
var parseFn;
|
||||
if (isDefined(expression)) {
|
||||
parseFn = $parse(expression);
|
||||
if (!parseFn.constant) {
|
||||
throw new minErr('ngModel')('constexpr', 'Expected constant expression for `{0}`, but saw ' +
|
||||
'`{1}`.', name, expression);
|
||||
}
|
||||
return parseFn(context);
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (!isString(trueValue)) trueValue = true;
|
||||
if (!isString(falseValue)) falseValue = false;
|
||||
function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
|
||||
var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
|
||||
var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
|
||||
|
||||
var listener = function(ev) {
|
||||
scope.$apply(function() {
|
||||
@@ -1208,7 +1218,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
|
||||
};
|
||||
|
||||
ctrl.$formatters.push(function(value) {
|
||||
return value === trueValue;
|
||||
return equals(value, trueValue);
|
||||
});
|
||||
|
||||
ctrl.$parsers.push(function(value) {
|
||||
@@ -1356,14 +1366,15 @@ function checkboxInputType(scope, element, attr, ctrl) {
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
var inputDirective = ['$browser', '$sniffer', '$filter', function($browser, $sniffer, $filter) {
|
||||
var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
|
||||
function($browser, $sniffer, $filter, $parse) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: ['?ngModel'],
|
||||
link: function(scope, element, attr, ctrls) {
|
||||
if (ctrls[0]) {
|
||||
(inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
|
||||
$browser, $filter);
|
||||
$browser, $filter, $parse);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2528,8 +2528,8 @@ describe('input', function() {
|
||||
|
||||
|
||||
it('should allow custom enumeration', function() {
|
||||
compileInput('<input type="checkbox" ng-model="name" ng-true-value="y" ' +
|
||||
'ng-false-value="n">');
|
||||
compileInput('<input type="checkbox" ng-model="name" ng-true-value="\'y\'" ' +
|
||||
'ng-false-value="\'n\'">');
|
||||
|
||||
scope.$apply(function() {
|
||||
scope.name = 'y';
|
||||
@@ -2554,6 +2554,27 @@ describe('input', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should throw if ngTrueValue is present and not a constant expression', function() {
|
||||
expect(function() {
|
||||
compileInput('<input type="checkbox" ng-model="value" ng-true-value="yes" />');
|
||||
}).toThrowMinErr('ngModel', 'constexpr', "Expected constant expression for `ngTrueValue`, but saw `yes`.");
|
||||
});
|
||||
|
||||
|
||||
it('should throw if ngFalseValue is present and not a constant expression', function() {
|
||||
expect(function() {
|
||||
compileInput('<input type="checkbox" ng-model="value" ng-false-value="no" />');
|
||||
}).toThrowMinErr('ngModel', 'constexpr', "Expected constant expression for `ngFalseValue`, but saw `no`.");
|
||||
});
|
||||
|
||||
|
||||
it('should not throw if ngTrueValue or ngFalseValue are not present', function() {
|
||||
expect(function() {
|
||||
compileInput('<input type="checkbox" ng-model="value" />');
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
|
||||
it('should be required if false', function() {
|
||||
compileInput('<input type="checkbox" ng:model="value" required />');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user