3

I have a <select> element that uses ng-options to generate the select list and hopefully set the selected to the value of the ng-model. Here is my html:

<td style="text-align:center">
    <ng-form name="IsTobaccoForm">
        <select name="Input" required ng-model="dep.IsTobacco" ng-options="item.value as item.text for item in yesNoList"></select>{{dep.IsTobacco}}
        <span class="alert-error" ng-show="IsTobaccoForm.Input.$error.required"><strong>*Required</strong></span>
    </ng-form>
</td>

My controller contains the following code:

$scope.yesNoList = [{ value: true, text: 'Y' }, { value: false, text: 'N'}];

If the IsTobacco value of the item is true, the value is set properly and everything is fine. However, if it is false, the required error appears, even though {{dep.IsTobacco}} renders as false. The really weird part is that if I change the selected item in the list to true, it works fine, however if I set it to false, a new blank item is added to the list and that blank item is selected.

If it seems like the issues do not lie in the lines posted above, I could gladly post more code.

Thanks!

EDIT: I also used chrome debugger and saw that when the data was being initiated in Angular, the value of IsTobacco was equal to false.

Edit 2: If anyone viewing this is new to AngularJS, I would definitely recommend reading these 2 articles: part 1 & part 2. They are an overview of AngularJS forms.

Dan
  • 59,490
  • 13
  • 101
  • 110
PFranchise
  • 6,642
  • 11
  • 56
  • 73
  • 1
    For some reason (possibly related to checkboxes?), a value of `false` gets interpreted as a lack of `ngModel` when used with `required` - https://github.com/angular/angular.js/issues/2436. One workaround would be to use the string 'true' and 'false' instead. – Dan Jun 18 '13 at 01:49
  • @sh0ber oh man. That is not good haha. Thanks for the info on this. I had been forcing myself to not hack out a workaround assuming it was my lack of angular knowledge that was causing the issue. – PFranchise Jun 18 '13 at 01:55
  • No problem, I didn't realize this myself. It probably doesn't need to be this way, considering that checkboxes can take `ng-true-value` and `ng-false-value` attributes. But I guess it was either this or enforce the use of non-true and non-false values for those attributes on every checkbox, and this was the better choice. – Dan Jun 18 '13 at 02:07
  • Ya, that definitely makes sense. I had not considered the ramifications when using `ng-options` with checkboxes. – PFranchise Jun 18 '13 at 02:12
  • 1
    Posted as an answer now :) – Dan Jun 18 '13 at 02:20

1 Answers1

3

The reason this happens is because a value of false gets interpreted as a lack of ngModel when used with required. As discussed here, consider this excerpt from the Angular source:

var validator = function(value) {
    if (attr.required && (isEmpty(value) || value === false)) {
        ctrl.$setValidity('required', false);

If there is a required attribute and its value is false, it does not pass validation. This is probably intentional for the sake of more easily validating required checkboxes, in which case the default value for unchecked is false.

It may not need to be this way, considering that checkboxes can take ng-true-value and ng-false-value attributes but I guess it was either do this or enforce the use of non-true and non-false values for those attributes on every checkbox, and this was the better choice.

One workaround would be to use the strings 'true' and 'false' instead.

Dan
  • 59,490
  • 13
  • 101
  • 110
  • sh0ber has already mentioned the use of checkboxes but I feel this should be stressed further. I changed my code to use 'Yes' and 'No', and then realised I was hacking when I needn't. Use checkboxes. – Jack Dec 29 '14 at 14:41