入力ダイアログで入力された値のサーバーでの検証エラーの表示

ASP.NET MVC と jQuery で新規登録ダイアログと編集ダイアログ」でダイアログ上での新規登録とデータの編集を行ったわけですが、その際にサーバー側でのデータ検証でエラーを把握した場合に、単純にデータ入力画面(この場合はダイアログ表示)に戻せないと書きました。実際そのとおりなのですが、サーバー側のデータを使わないと検証できないものがあるのも事実です(ページング表示でクライアント側にすべてのデータが渡されていない場合のデータの重複確認など)。

そこで、サーバー側でデータ検証エラーを把握した際に、データ入力のダイアログを再表示させる方法を考えてみました。データ検証でエラーが発生した場合、エラーメッセージと入力データをビューへ渡し、クライアント側では受け取った HTML ドキュメントからエラー発生を把握して、入力されていたデータをフォームにセットしてからダイアログを表示させれば、うまくできそうです。

動かしてみた結果は、次のとおりです。制約事項として、「メールアドレスの重複はダメ」としました。

新規登録で重複するデータを入力
エラー通知とともにダイアログを再表示

まずは、モデル(TestModel.cs)の CreateContact メソッドにメールアドレスの存在チェックを組み込みます。同一メールアドレスが既に登録されていた場合には ValidationException を投げるようにします。


        static public void CreateContat(DataModel dataModel)
        {
            if (_dataModel.Where(c => c.Email == dataModel.Email).Count() != 0)
                throw new ValidationException("同一のメールアドレスが既に登録されているので追加できませんでした。");
            dataModel.Id = _dataModel.Max(n => n.Id) + 1;
            _dataModel.Add(dataModel);
        }

次はコントローラー(HomeController.cs) の CreateContact(DataModel model) アクションに、ValidationException が発生したときにビューへエラーメッセージと入力データを渡すコードを組み込みます。


        [HttpPost]
        public ActionResult CreateContact(DataModel model)
        {
            try
            {
                TestModel.CreateContat(model);
            }
            catch (ValidationException e)
            {
                TempData["createErr"] = e.Message;
                TempData["model"] = model;
            }
            return RedirectToAction("ListContacts");
        }

最後にビュー(ListContacts.cshtml)です。フォームの入力エリアへのデータセット、<div id=”createDialog” style=”display:none;”>の次の行にエラーメッセージの表示領域の確保、そして、エラーメッセージと入力データが渡されたときに、渡された入力データのセットとダイアログ表示を行う JavaScript のセットを行うコードを組み込みます。

@model IEnumerable<TestJqueryUi004.Models.DataModel>

@{
    ViewBag.Title = "連絡先一欄";
}

@section scripts {
<script type="text/javascript">
<!--
    function showCreateDialog() {
        $("#createDialog").dialog({
            title: "新規作成",
            width: 550,
            height: 400,
            modal: true,
            buttons: {
                "作成": function () {
                    $("#createDialog form").submit();
                    if ($("#createDialog form").valid()) {
                        $(this).dialog("close");
                    }
                },
                "キャンセル": function () {
                    $(this).dialog("close");
                }
            },
            close: function () {
                $(this).dialog("destroy");
            }
        });
    }

    function showEditDialog(id, name, email, phone) {
        setForm("#editDialog", id, name, email, phone);
        $("#editDialog").dialog({
            title: "連絡先編集",
            width: 550,
            height: 400,
            modal: true,
            buttons: {
                "更新": function () {
                    $("#editDialog form").submit();
                    if ($("#editDialog form").valid()) {
                        $(this).dialog("close");
                    }
                },
                "キャンセル": function () {
                    $(this).dialog("close");
                }
            },
            close: function () {
                $(this).dialog("destroy");
            }
        });
    }

    function setForm(selector, id, name, email, phone) {
        $(selector + " form")
            .find("input[id=Id]").val(id)
            .end()
            .find("input[id=Name]").val(name)
            .end()
            .find("input[id=Email]").val(email)
            .end()
            .find("input[id=Phone]").val(phone);
    }
//-->
</script>
}

<h2>@ViewBag.Title</h2>

<div style="color: Red">@Html.Encode(TempData["editErr"])</div>

<p>
    <a href="#" onclick="showCreateDialog()">連絡先の作成</a>
</p>
<table>
    <tr>
        <th>
            名前
        </th>
        <th>
            メールアドレス
        </th>
        <th>
            電話番号
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Email)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Phone)
        </td>
        <td>
            <a href="#" onclick="showEditDialog('@item.Id', '@item.Name', '@item.Email', '@item.Phone')">編集</a> |
            @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
        </td>
    </tr>
}

</table>

<div id="createDialog" style="display:none;">
<div style="color: Red">@Html.Encode(TempData["createErr"])</div>
@Html.Action("CreateContact")
</div>
<div id="editDialog" style="display:none;">
@Html.Action("EditContact")
</div>
<div style="display:none">
@if (TempData["createErr"] != null)
{
    <script type="text/javascript">
        $(
            function () {
                showDialogWithErr("#createDialog");
            }
        );
    </script>
}
@if (TempData["model"] != null)
{
    var errData = (TestJqueryUi004.Models.DataModel)TempData["model"];
    <script type="text/javascript">
        function showDialogWithErr(selector) {
            var errData = $("#errData");
            setForm(selector, 0, errData.find("div[class=name]").text(),
                errData.find("div[class=email]").text(), errData.find("div[class=phone]").text());
            if (selector == "#createDialog")
                showCreateDialog();
            else
                showEditDialog();
        }
    </script>
    <div id="errData">
        <div class="name">@Html.Encode(errData.Name)</div>
        <div class="email">@Html.Encode(errData.Email)</div>
        <div class="phone">@Html.Encode(errData.Phone)</div>
    </div>
}
</div>

showDialogWithErr(“#createDialog”); の呼び出しは jQuery の ready イベントで行うようにしています(省略表記で記述)。

 

とりあえず、こんな感じで動いています。なお、あくまで感触を掴むために書いたものなので、エラー・ハンドリングを省いています。もし参考にされる方がいらしたら、ちゃんとエラー処理をしてください 😉

何か気がついたこととかあったら、指摘していただけると嬉しいです 🙂


入力ダイアログで入力された値のサーバーでの検証エラーの表示」への2件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。