お遊びを離れ、何かやろうとすると直ぐにカスタムバリデートが必要になるので、そのやり方。
1.3から簡単になったらしいが、その前を知らないので、感動は薄い。
普通?のバリデーションに加え、サーバを非同期で見に行くバリデーションも作れる。ユーザーの一意性チェックなどには重宝するだろう。
###やること
- nameには、普通?のバリデーションんを書けている(全部小文字じゃないとだめ)
- nicknameはサーバに問合せ、ユニークかどうかをチェックする(サーバはokかngを返すイメージ)
###ポイントと課題
非同期のバリデーションはngModel.$asyncValidatorsを使うことで実現できる。また、全部入力時に初めて評価したいため、ng-model-options="{updateOn: 'blur'}"により、フォーカスが外れた時にチェックがかかるようにしている(が、そうならない)。
ng-model-options="{updateOn: 'blur'}"をつけていても、初回読み込み時に1度実行されてしまう。何かやり方がおかしいのだろうけど、初回時は値がundefinedなので、それで判断して場合分けしている・・・。うーん。
あと、ngModel.$asyncValidatorsの返り値はpromise(then...)じゃないとだめ。最初、直接true,falseを返していてしばらくハマった。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script>
var app = angular.module('myApp',[]);
app.controller('myCtrl',function($scope){
//function
$scope.addUser = function(){
alert("added");
}
});
//普通?のバリデーション
app.directive('usernameValidator',function(){
return{
restrict: "A",
require: "ngModel",
link: function(scope,element,attrs,ngModel){
ngModel.$validators.username = function(modelValue,viewValue){
var value = modelValue || viewValue;
return /^[a-z]+$/.test(value);
}
}
}
});
//サーバを見に行くバリデーション
app.directive('nicknameValidator',function($http,$q){
return{
restrict: "A",
require: "ngModel",
link: function(scope,element,attrs,ngModel){
//戻り値はpromiseでなくてはならない(直true, false)ではNGになる。
ngModel.$asyncValidators.nickname = function(modelValue,viewValue){
var value = modelValue || viewValue;
//読み込時は何もしない(''とすると何もしないのでそうしている。なにかよい方法がないか・・・)
if(value == undefined){
return $http.get('').then(function(){
},function(){
});
}
//on blurで非同期チェック
return $http.get('res.php').then(function(res){
if(res.data == "ok"){
return true;
}else{
return $q.reject();
}
});
}
}
}
});
</script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<form novalidate name="myForm" ng-submit="addUser()">
<!-- text -->
<p>
Name:<input type="text" name="name" ng-model="name" username-validator>
<span ng-show="myForm.name.$error.username">name contain only lowercharactors.</span>
</p>
<p>
NickName:<input type="text" name="nickname" ng-model="nickname" nickname-validator ng-model-options="{updateOn: 'blur'}">
<span ng-show="myForm.nickname.$error.nickname">aleady exits.</span>
</p>
<!-- submit -->
<p><input type="submit" value="add"></p>
<pre>{{name}}</pre>
</form>
</body>
</html>