AngularJS select doesn't error when model value not in options

安稳与你 提交于 2019-12-23 17:27:49

问题


Angular 1.4.8.

I have this markup for 2-letter US state codes:

<div class="form-group" ng-class="{'has-error': form.licenseState.$invalid }">
    <label for="licenseState" class="control-label">License State</label>
    <select name="licenseState" id="licenseState" class="form-control" required
            ng-model="ctrl.student.License.State"
            ng-options="key as key for (key, value) in ctrl.licenseFormats">
    </select>
</div>

This properly gives me an error when the model value is loaded as blank.

However, when the model value is loaded as a value not in the list (bad data), it does not error.

The situation baffles me considering the result is misinformation at all levels. User sees a blank value which appears to be valid (despite required attribute). Model sees a different value from user which appears to be valid even though it's absent from the valid values list.

Am I missing something? Is there a proper (canonical angular) way to make this trigger a form validation error?


Update

Based on the answer from @paul147, I ended up with this reusable directive for validating a model value against a list.

m.directive('validValues', function() {
    return {
        scope: {
            validValues: '='
        },
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attributes, ngModel) {
            var values = angular.isArray(scope.validValues)
                ? scope.validValues
                : Object.keys(scope.validValues);
            ngModel.$validators.validValues = function (modelValue) {
                return values.indexOf(modelValue) !== -1;
            }
        }
    }
});

Example usage:

<select name="licenseState" required valid-values="ctrl.licenseFormats"
        ng-model="ctrl.student.License.State"
        ng-options="key as key for (key, value) in ctrl.licenseFormats">
</select>

I briefly explored getting the options directly from the select element, but ngOptions puts the values in a custom format. F.ex string:AL (which is actually a lookup key) for the value of AL. Further discussion here. Ultimately, the directive is more reusable with less effort if I just do it as above with the redundant declaration of valid values (ctrl.licenseFormats in this case).


回答1:


One thing you can do to trigger errors on the ngModel directive is to add a custom validator to the ngModel's $validators.

The ngModel's value is passed through the $validators whenever it changes, and an error is raised if the validator returns false.

An example implementation is to add a custom directive to the model's element, and define the validator inside that directive:

Here's a plunkr with a working example: http://plnkr.co/edit/m6OygVR2GyMOXTTVTuhf?p=preview

// markup
<select name="licenseState" id="licenseState" class="form-control" required
  ng-model="student.License.State"
  ng-options="key as value for (key, value) in licenseFormats"
  check-state
  license-formats="licenseFormats">

// in the controller
$scope.licenseFormats = {
  'OR': 'Oregon', 
  'WA': 'Washington', 
};     

// the directive
app.directive('checkState', function() {
  return {
    scope: {
      licenseFormats: '='
    }, 
    restrict: 'A', 
    require: 'ngModel', 
    link: function(scope, element, attributes, ngModel) {

      // defining the validator here
      ngModel.$validators.state = function(modelValue) {
        return Object.keys(scope.licenseFormats).indexOf(modelValue) > -1;
      }
    }
  }
});


来源:https://stackoverflow.com/questions/35068507/angularjs-select-doesnt-error-when-model-value-not-in-options

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!