AngularJs 原生的 select option 的 required 驗證,
只能對 ng-model 的值為 undefined , "", null , NaN來做 required error。
參考:
ngModel.NgModelController 的 $isEmpty
但如果 ng-model 不是 undefined , "", null , NaN ,且其值不在 select option 中,
此時希望能檢查出驗證錯誤的話 (validation) ,
就需要自己實作。
例如可能的情境為:
如果 option list 裡都是不為 0 的數字,當 ng-model 是數字 0 時 (可能是程式常態 assign 賦值的),此時 required (或 ng-required) 就無法驗證出 required 的 validation error。
以下為我寫出來的簡單實作,
建立了一個名為 selectOptionCheckValidator 的 directive 來進行驗證:
html :
<div ng-app="app" ng-controller="controller as ctrl">
<form name="form">
<label><input type="radio" name="optionType" ng-value="1" ng-model="ctrl.optionType" /> Set option list 1</label>
<label><input type="radio" name="optionType" ng-value="2" ng-model="ctrl.optionType" /> Set option list 2</label>
<select name="mySelector" ng-model="ctrl.selectedVal" ng-options="selectOption.optionValue.id as selectOption.title for selectOption in ctrl.selectOptionList" select-option-check-validator ng-required="true">
</select>
<button ng-click="ctrl.selectedVal = 0">
Set selectedVal to 0
</button>
<div>
ctrl.selectedVal : {{ctrl.selectedVal}}
</div>
<div>
form.mySelector.$error.selectedValueInOptionList : {{form.mySelector.$error.selectedValueInOptionList ? "invalid" : "valid"}}
</div>
<div>
form.mySelector.$error.selectedValueInOptionList : {{form.mySelector.$error.required ? "invalid" : "valid"}}
</div>
</form>
</div>
angular.module("app", [])
.controller("controller", ["$scope", function($scope) {
var self = this;
self.optionType = 1;
self.selectedVal = 0;
self.optionList1 = [{
optionValue: {
id: 11
},
title: "id 11"
}, {
optionValue: {
id: 12
},
title: "id 12"
}];
self.optionList2 = [{
optionValue: {
id: 21
},
title: "id 21"
}, {
optionValue: {
id: 22
},
title: "id 22"
}];
self.selectOptionList = [];
$scope.$watch(angular.bind(this, function() {
return this.optionType;
}), function(newVal, oldVal) {
//if value of selectedValue can not be found in self.selectOptionList,
// selectedValue will be assigned to null.
if (newVal == 1) {
self.selectOptionList = self.optionList1;
} else if (newVal == 2) {
self.selectOptionList = self.optionList2;
self.selectedVal = 21;
}
});
}]).directive('selectOptionCheckValidator', ["$parse", function($parse) {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
var regex = /(.+)\sas\s(.+)\sfor\s(.+)\sin\s(.+)/;
var matchString = regex.exec(attrs.ngOptions);
var collectionExpression = matchString[4]; // "ctrl.selectOptionList"
var arryItemVarableName = matchString[3]; // "selectOption"
var valueExpression = matchString[1]; // "selectOption.optionValue.id"
scope.$watch(collectionExpression, function(newValue, oldValue) {
checkIsSelectedValueInOptionList();
});
element.on("change", function() {
scope.$apply(function() {
checkIsSelectedValueInOptionList();
});
});
function checkIsSelectedValueInOptionList() {
var isSelectedValueInOptionList = false;
var selectedValue = $parse(attrs.ngModel)(scope);
var optionList = $parse(collectionExpression)(scope);
if (optionList) {
isSelectedValueInOptionList = optionList.some(function(option) {
// create a custom scope object to render optionValue from valueExpression
var optionTempObject = new function(){
this[arryItemVarableName] = option;
};
var optionValue = $parse(valueExpression)(optionTempObject);
return optionValue == selectedValue;
});
ngModel.$setValidity("selectedValueInOptionList", isSelectedValueInOptionList);
}
}
}
};
}]);
在這個例子裡,設置了兩個 option list 作為 <select> 的 option 選項,
Note
此例中用來解析 ng-option 字串的正規表達式較為簡易,
如果想知道完整的正規表達式,也就是可以解析 AngularJs ng-option 所有可能字串的正規達式,
可以參考官方源碼,其中可以看到正規表達式為:
^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([$\w][$\w]*)|(?:\(\s*([$\w][$\w]*)\s*,\s*([$\w][$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$
圖例:

沒有留言 :
張貼留言