AngularJS select 当模型值不在选项中时不会出错
AngularJS select doesn't error when model value not in options
Angular 1.4.8.
我有这个 2 个字母的美国州代码标记:
<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>
当模型值加载为空白时,这正确地给我一个错误。
但是,当模型值加载为不在列表中的值(错误数据)时,它不会出错。
考虑到结果是所有级别的错误信息,这种情况让我感到困惑。用户看到一个似乎有效的空白值(尽管 required
属性)。模型看到与用户不同的值,该值似乎有效,即使它不在有效值列表中。
我错过了什么吗?是否有适当的(规范的angular)方法使此触发器成为表单验证错误?
更新
根据@paul147 的回答,我最终得到了这个可重复使用的指令,用于根据列表验证模型值。
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;
}
}
}
});
用法示例:
<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>
我简要探索了直接从 select 元素获取选项,但 ngOptions 将值置于自定义格式中。 F.ex string:AL
(实际上是查找键)为AL
的值。进一步讨论 。最终,如果我只是像上面那样使用有效值的冗余声明(在本例中为 ctrl.licenseFormats
),那么该指令可以更轻松地重用。
要触发 ngModel 指令错误,您可以做的一件事是向 ngModel 的 $validators 添加自定义验证器。
ngModel 的值在更改时通过 $validators 传递,如果验证器 returns false 则会引发错误。
一个示例实现是向模型的元素添加自定义指令,并在该指令中定义验证器:
这是一个带有工作示例的 plunkr: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;
}
}
}
});
Angular 1.4.8.
我有这个 2 个字母的美国州代码标记:
<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>
当模型值加载为空白时,这正确地给我一个错误。
但是,当模型值加载为不在列表中的值(错误数据)时,它不会出错。
考虑到结果是所有级别的错误信息,这种情况让我感到困惑。用户看到一个似乎有效的空白值(尽管 required
属性)。模型看到与用户不同的值,该值似乎有效,即使它不在有效值列表中。
我错过了什么吗?是否有适当的(规范的angular)方法使此触发器成为表单验证错误?
更新
根据@paul147 的回答,我最终得到了这个可重复使用的指令,用于根据列表验证模型值。
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;
}
}
}
});
用法示例:
<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>
我简要探索了直接从 select 元素获取选项,但 ngOptions 将值置于自定义格式中。 F.ex string:AL
(实际上是查找键)为AL
的值。进一步讨论 ctrl.licenseFormats
),那么该指令可以更轻松地重用。
要触发 ngModel 指令错误,您可以做的一件事是向 ngModel 的 $validators 添加自定义验证器。
ngModel 的值在更改时通过 $validators 传递,如果验证器 returns false 则会引发错误。
一个示例实现是向模型的元素添加自定义指令,并在该指令中定义验证器:
这是一个带有工作示例的 plunkr: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;
}
}
}
});