diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 6a974d9dae02..cf0a0f1625d4 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -657,12 +657,9 @@ function radioInputType(scope, element, attr, ctrl) { attr.$observe('value', ctrl.$render); } -function checkboxInputType(scope, element, attr, ctrl) { - var trueValue = attr.ngTrueValue, - falseValue = attr.ngFalseValue; - - if (!isString(trueValue)) trueValue = true; - if (!isString(falseValue)) falseValue = false; +function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $parse) { + var trueValue = getCheckedValue(attr.ngTrueValue, true), + falseValue = getCheckedValue(attr.ngFalseValue, false); element.on('click', function() { scope.$apply(function() { @@ -676,16 +673,31 @@ function checkboxInputType(scope, element, attr, ctrl) { // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox. ctrl.$isEmpty = function(value) { - return value !== trueValue; + return !equals(value, trueValue); }; ctrl.$formatters.push(function(value) { - return value === trueValue; + return equals(value, trueValue); }); ctrl.$parsers.push(function(value) { return value ? trueValue : falseValue; }); + + function getCheckedValue(expr, defaultValue) { + if (isString(expr)) { + var getter = $parse(expr), + value = getter(scope); + // If the resulting value is undefined, and not the constant `undefined`, then + // return the original string expression, it was probably intended as a string + // literal. + if (isUndefined(value) && !getter.constant) { + return expr; + } + return value; + } + return defaultValue; + } } @@ -812,14 +824,14 @@ function checkboxInputType(scope, element, attr, ctrl) { */ -var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) { +var inputDirective = ['$browser', '$sniffer', '$parse', function($browser, $sniffer, $parse) { return { restrict: 'E', require: '?ngModel', link: function(scope, element, attr, ctrl) { if (ctrl) { (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer, - $browser); + $browser, $parse); } } }; diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 48319cfaf2ff..54f456a8e4c9 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -1082,6 +1082,48 @@ describe('input', function() { }); + it('should parse numeric ng-true-value/ng-false-value', function() { + compileInput(''); + scope.$apply(function() { + scope.value = 12345; + }); + expect(inputElm[0].checked).toBe(true); + + scope.$apply(function() { + scope.value = 0; + }); + expect(inputElm[0].checked).toBe(false); + + browserTrigger(inputElm, 'click'); + expect(scope.value).toBe(12345); + + browserTrigger(inputElm, 'click'); + expect(scope.value).toBe(0); + }); + + + it('should parse object ng-true-value/ng-false-value', function() { + compileInput(''); + scope.$apply(function() { + scope.value = {num: 12345}; + }); + expect(inputElm[0].checked).toBe(true); + + scope.$apply(function() { + scope.value = null; + }); + expect(inputElm[0].checked).toBe(false); + + browserTrigger(inputElm, 'click'); + expect(scope.value.num).toBe(12345); + + browserTrigger(inputElm, 'click'); + expect(scope.value).toBe(null); + }); + + it('should be required if false', function() { compileInput('');