javascripthtmlangularjsng-optionsangularjs-forms

AngularJS - ng-option dropdown list not setting ng-model value when False selected


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.


Solution

  • 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.