クライアントでバリデーション
前回作った新規入力フォームにバリデーション機能を付けてみたので、コツっぽいものをメモ。
ポイント的には
- フォームやフォーム部品には名前(name属性)を付ける。
- $errorや$validの評価はエレメントにつけた名前で行う。
ぐらいでしょうか。
フォームの入力要素にAngularJSから提供されてるバリデーション用のdirectiveを記述しとくとバリデートしてくれます。
たとえばinputには ng-required,ng-minlength,ng-maxlength,ng-pattern が使えるようです。詳しくはリファレンス見ましょうってことですかね。
View
入力フォーム用のViewはこんな風にしました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
<!doctype html>
<html ng-app="myApp">
<head>
<script src="@Url.Content("~/Scripts/angular.min.js")"></script>
・・・中略・・・
<style type="text/css">
/*invalidな時のスタイル。編集後のみ効くようにng-dirtyを付ける*/
input.ng-invalid.ng-dirty { border: 1px solid red !important; }
</style>
</head>
<body>
<div ng-controller="TasksController">
・・・中略・・・
<hr>
<form class="form-horizontal" role="form" ng-model='newTask' novalidate name="newTaskForm">
<div class="form-group">
<div ng-controller="DatepickerCtrl">
<label for="newDueDate" class="col-sm-2 control-label">締切日</label>
<div class="col-sm-6">
<p class="input-group">
<input type="text" class="form-control" ng-model="newTask.DueDate" id="newDueDate"
datepicker-popup="yyyy-MM-dd" is-open="opened" datepicker-options="dateOptions" date-disabled="disabled(date, mode)"
ng-required="true" />
<span class="input-group-btn">
<button class="btn btn-default" ng-click="open($event)">
<i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
</div>
<div class="form-group">
<label for="newDescription" class="col-sm-2 control-label">詳細</label>
<div class="col-sm-10">
<input type="text" ng-model="newTask.Description" placeholder="Input Description" id="newDescription" name="txtNewDescription"class="form-control"
ng-required="true" ng-maxlength="50"
/>
<span ng-show="newTaskForm.txtNewDescription.$error.maxlength">too long</span>
<span ng-hide="newTaskForm.txtNewDescription.$error.maxlength">{{50-newTask.Description.length}}</span>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button ng-click="add(newTask,newTaskForm)" class="btn btn-primary" ng-disabled="!newTaskForm.$valid">追加</button>
</div>
</div>
{{newTask}}
</form>
</div>
<hr>
・・・中略・・・
</body>
</html>
|
8行目:エラーがある要素にはng-invalidってクラスが付与されるっぽいので、スタイルを設定。
15行目:fromにはnameとnovalidateを設定します。
23,37行目:バリデーション用のdirectiveです。必須と長さ制限。
39,40行目:フォーム要素(modelでは無い)を評価してエラーメッセージとか出してます。
45行目:ng-disabled="!newTaskForm.$valid"
でフォームが正しくない時はサブミットできなくしてます。
controller
コントローラは、新規追加後にフォームをクリアする処理を追加しました。
1
2
3
4
5
6
7
|
$scope.add = function (task, newForm) { //追加処理
aTasks.save({ Description: task.Description, DueDate: task.DueDate }, function (saved_object) {
$scope.Tasks.push(saved_object); //成功ハンドラの第一引数にWebAPIの返り値が入るっぽい。
$scope.newTask = {}; //入力内容初期化
newForm.$setPristine(); //フォームもリセット
});
};
|
実行するとこんな感じです。
枠が赤くなって、エラーメッセージ(too long)が出て追加ボタンが押せなくなってます。
ほぼコードを書くことなく動いちゃうところが凄いですな。
サーバ側バリデーション
バリデーションというかエラーハンドリングです。
変な入力があったらexceptionをthrowして、クライアントで表示するようにしてみます。
controller(サーバ)
WebAPIのコントローラにバリデーションロジックを追加します。
ロジック的には新規作成の時にDescriptionに”ぬるぽ”が含まれてたら”ガッ”例外を発生させるというあほらしいものです。
1
2
3
4
5
6
7
8
9
10
11
|
// POST api/tasks 新規作成
public Models.Task Post(Models.Task value) {
if (value.Description.Contains("ぬるぽ")) {
throw new ApplicationException("ガッ");
}
using (var db = new Models.TaskContext()) {
db.Tasks.Add(value);
db.SaveChanges();
return value; //保存された値を返す
}
}
|
controller(AngularJS)
クライアント側のコントローラにAJAX呼び出しの際のエラーハンドラを追加します。
1
2
3
4
5
6
7
8
9
10
11
|
$scope.add = function (task, newForm) { //追加処理
aTasks.save({ Description: task.Description, DueDate: task.DueDate }, function (saved_object) {
$scope.Tasks.push(saved_object); //成功ハンドラの第一引数にWebAPIの返り値が入るっぽい。
$scope.newTask = {}; //入力内容初期化
newForm.$setPristine(); //フォームもリセット
},
function (httpResponse) { //エラーハンドら
$scope.DebugObj = httpResponse;
alert(httpResponse.data.ExceptionMessage);
});
};
|
いじょうですけど。