ここで議論するのは、次の二つです。
まず、第一項目です。エラーの発生元には、以下の場合があります。
サーバーで発生したエラーは、サーバー側で対処するしかありません。この場合の残る問題は、そのエラーをどうやってユーザに知らせるかとなります。
一方、ブラウザで発生したエラーは次の3通りの対処方法があります。
このプログラムでは、上記の一番目の方法を採用します。ブラウザ上で jQuery を使用して検査しますので、サーバーにデータを送信して、その結果を受信するのと比較して、応答時間が短くなります。
また、三番目のブラウザとサーバーでの2重チェックが必要なほど、重要度が高いデータを扱っているわけでもないからです。こうした方針は、そのプロジェクト毎に異なるでしょう。
金銭や個人情報を扱うようなアプリケーションの場合は、慎重な検討が必要でしょう。
ここまでの結論を踏まえて、第二項目の「エラーをどうやってユーザに知らせるか」を議論すると、問題は次の2つになります。
議論しなければいけないエラー処理は、次の2つにまとまりました。
どのようなエラーであっても、ユーザにエラーの発生を伝えるためには、ブラウザ上にエラーを表示するしかありません。 そこで、エラーの表示はすべて次のようにします。
エラー内容を、画面のタイトルの直下に、薄い赤を背景に赤文字で表示する
次のような、エラーを表示する専用のタグを用意します。このタグは、サーバーで発生したエラーだけでなく、ブラウザで発生したエラーの表示にも使用します。
サーバーで発生したエラーは、 id 属性値 Mrror-Message を持つこのタグに埋め込みます。一方、ブラウザで発生したエラーは jQuery を使用して、このタグにエラー内容を埋め込みます。
1 <div id="Error-Message" class="bg-danger text-danger">
2 </div>
ここで、id 属性の値「 Error-Message 」は固定です。 bg-danger と text-danger は bootstrap で定義された CSS の値で、 それぞれ背景色と文字色を指定しています。
このタグにサーバーでエラー内容を表示するために、以下のメソッドを利用します。
1 protected void DisplayErrors(string txt, bool flag = true, string selector = "#Error-Message")
2 {
3 String[] lines;
4 String[] limit = { "。" };
5 if (flag)
6 lines = txt.Split(limit, StringSplitOptions.None);
7 else
8 {
9 lines = new String[1];
10 lines[0] = txt;
11 }
12 String text = lines[0].Replace("\"", "\\\"");
13 text = text.Replace("\'", "\\\'");
14 ClientScript.RegisterClientScriptBlock(this.GetType(),
15 "",
16 String.Format("<script type='text/javascript'>" +
17 "$('{0}').append('<p>{1}</p>');" +
18 "</script>", selector, text));
19 }
1行目:引数 txt はエラーメッセージの本文、 flag はメッセージ中に句点があるとき1行目だけを有効とするかどうか、selector は表示用タグの id 属性値で上記の説明のように Error-Message 固定です
3~11行目:メッセージ中に句点がある場合の処理。句点も含めて全体を表示するか、句点の前だけを表示するかを切り分けています
12~13行目:メッセージ中にダブルクウォートやシングルクウォートがある場合の特殊処理
14~18行目:エラー表示エリアにメッセージを表示するための jQuery プログラムの埋め込み
上記メッセージの中心部分は、14~18行目になります。
次のような、エラーを表示する専用のタグを <body> タグの後のタイトルの直後に用意します。 このタグは、サーバーで発生したエラーの表示にも使用します。
1 <div id="Error-Message" class="bg-danger text-danger">
2 </div>
例えば、追加ボタン(AddButton)をクリックした場合のエラー検査は次のようにします。
1 <script>
2 $(function () {
3 $("#AddButton").click(function () {
4 $("#Error-Message").text("");
5 if ($("#InputId").isNull()) {
6 $("#Error-Message").append("<p>IDは必須項目です。</p>");
7 }
8 return $("#Error-Message").text().length == 0;
9 });
10 });
11 </script>
5行目:未入力かどうかの検査。 isNull() はそのための jQuery の自作関数。 jQuery の自作関数に関しては、 こちら を参照してください
6行目:エラーの場合に、エラー表示エリアにメッセージを追加
8行目: true を返すと、サーバーにサブミットし、 false を返すとサブミットしないので、エラーメッセージが空文字列かどうかを検査する
Web Form と同じく、議論しなければいけないエラー処理は、次の2つにまとまりました。
どのようなエラーであっても、ユーザにエラーの発生を伝えるためには、ブラウザ上にエラーを表示するしかありません。 そこで、エラーの表示はすべて次のようにします。これも、 Web Form と同じ結論です。
エラー内容を、画面のタイトルの直下に、薄い赤を背景に赤文字で表示する
次のような、エラーを表示する専用のタグを <body> タグの後の、タイトルの直後に用意します。このタグは、ブラウザで発生したエラーの表示にも使用します。
@Html.ValidationSummary(false, "", new { id = "error-Message", @class = "text-danger bg-danger" })
これは、 MVC の html 記述用言語である Razor で用意されているエラー用タグの記述になります。
このタグにエラーメッセージを追加するには、Controller クラスのメソッドから以下のようにします。
ModelState.AddModelError(エラー本文のキーとなる文字列, エラーの本文);
ここで、 ModelState は標準の Controller クラスで定義されているオブジェクトです。そのオブジェクトに AddModelError() メソッドで エラーを追加すると、上記の @Html.ValidationSummary に表示されます。
ブラウザで発生したエラーも、上記の @Html.ValidationSummary に表示することにしました。そこで、 @Html.ValidationSummary がどのように html に変換されるかを見てみます。ただし、何もエラーが発生していない状態です。
<div class="validation-summary-valid text-danger bg-danger" data-valmsg-summary="true" id="error-Message">
<ul>
<li style="display:none"></li>
</ul>
</div>
<ul> タグに変換されていることが分かります。とすれば、 jQuery の関数は簡単です。ただし、このやりかたは @Html.ValidationSummary の実装に依存しています。
Web MVC の実装に依存しないようにするには、サーバーのエラーを表示するためのタグと、ブラウザのエラーを表示するためのタグを分ければよいです。2つのエラー表示用タグを上下に並べて配置すれば
表示上の違和感はないと思います。
エラー処理をどうするのかは、プロジェクト毎に判断してください。
1 <script>
2 $(function () {
3 $("#createButton").click(function () {
4 $("#error-Message > ul").text("");
5 if ($("#inputId").isNull()) {
6 $("#error-Message > ul").append("<li>IDは必須項目です。</li>");
7 }
8 return $("#error-Message > ul").text().length == 0;
9 });
10 });
11 </script>
<li> タグで整形したエラーメッセージを追加するだけです。
大分類を操作する画面でエラーが発生した場合の例を示します。(画像をクリックすると、拡大表示します)
必須項目である ID と名前が未入力の状態で、「追加」ボタンをクリックした時の画面になります。