diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js
index 6f3919dfb174..ca6a16a60d5d 100644
--- a/src/ng/directive/input.js
+++ b/src/ng/directive/input.js
@@ -1228,14 +1228,15 @@ var requiredDirective = function() {
attr.required = true; // force truthy in case we are on non input element
var validator = function(value) {
- if (attr.required && (isEmpty(value) || value === false)) {
+ if (attr.required && (isEmpty(value) || !acceptFalse && value === false)) {
ctrl.$setValidity('required', false);
return;
} else {
ctrl.$setValidity('required', true);
return value;
}
- };
+ },
+ acceptFalse = nodeName_(elm).toLowerCase() !== 'input' || attr.type !== 'checkbox';
ctrl.$formatters.push(validator);
ctrl.$parsers.unshift(validator);
diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js
index facc2b806bc9..fc861be0ac37 100644
--- a/test/ng/directive/inputSpec.js
+++ b/test/ng/directive/inputSpec.js
@@ -1093,7 +1093,25 @@ describe('input', function() {
compileInput('');
scope.$digest();
expect(inputElm).toBeInvalid();
- })
+ });
+
+ it('should allow `false` as a valid value when the input type is not "checkbox"', function() {
+ compileInput('' +
+ '');
+
+ scope.$apply();
+ expect(inputElm).toBeInvalid();
+
+ scope.$apply(function() {
+ scope.answer = true;
+ });
+ expect(inputElm).toBeValid();
+
+ scope.$apply(function() {
+ scope.answer = false;
+ });
+ expect(inputElm).toBeValid();
+ });
});
diff --git a/test/ng/directive/selectSpec.js b/test/ng/directive/selectSpec.js
index 5906ce99b38c..75d1d1e609aa 100644
--- a/test/ng/directive/selectSpec.js
+++ b/test/ng/directive/selectSpec.js
@@ -1198,6 +1198,30 @@ describe('select', function() {
});
expect(element).toBeValid();
});
+
+ it('should allow falsy values as values', function() {
+ createSelect({
+ 'ng-model': 'value',
+ 'ng-options': 'item.value as item.name for item in values',
+ 'ng-required': 'required'
+ }, true);
+
+ scope.$apply(function() {
+ scope.values = [{name: 'True', value: true}, {name: 'False', value: false}];
+ scope.required = false;
+ });
+
+ element.val('1');
+ browserTrigger(element, 'change');
+ expect(element).toBeValid();
+ expect(scope.value).toBe(false);
+
+ scope.$apply(function() {
+ scope.required = true;
+ });
+ expect(element).toBeValid();
+ expect(scope.value).toBe(false);
+ });
});
});