web-dev-qa-db-ja.com

jQuery検証、ASP.NET MVC ModelStateエラー(非同期POST)

Asp.net mvc 3を使用してWebアプリを開発していますが、非同期アクション(ajax経由)にPOST 。検証は正常に機能しますが、検証ツールがエラーを返したときに、ビューに表示するためにどのように返すことができるかわかりません(POSTはajaxによって作成されたため)。

私の行動は次のようなものです。

[HttpPost]
public ActionResult SaveCustomer(CustomerViewModel input) {
    if (!ModelState.IsValid) { // <-- business validation
        return Json(new { success = false, errors = ???});
    }
    // persist 
    return Json(new { success = true });
}

ビューでjqueryvalidateを使用してこのエラーを表示するにはどうすればよいですか?サンプルにコードを投稿することが可能であれば...私はそれを感謝します!

みんなありがとう!

23
Felipe Oriani

エラーの場合にJSONを送信する代わりに、フォームをパーシャル内に配置し、エラーの場合にコントローラーアクションがこのパーシャルを返すようにします。 JSONの問題は、実際にはLINQを使用してModelStateからエラーをフェッチできることですが、ビューにエラーを表示するのはPITAである可能性があります。

そう:

<div id="myform">
    @Html.Partial("_MyForm")
</div>

そして内部_MyForm.cshtml

@model CustomerViewModel
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.Foo)
    @Html.ValidationMessageFor(x => x.Foo)
    <br />
    @Html.EditorFor(x => x.Bar)
    @Html.ValidationMessageFor(x => x.Bar)
    <br />
    <input type="submit" value="OK" />
}

コントローラーのアクションは次のようになります。

[HttpPost]
public ActionResult SaveCustomer(CustomerViewModel model)
{
    if (!ModelState.IsValid)
    {
        return PartialView("_MyForm", model);
    }
    return Json(new { success = true });
}

最後のステップは、このフォームをAJAX化することです。これは、別のjavascriptファイルで実行できます。

$(function () {
    $('#myform').delegate('form', 'submit', function () {
        $.ajax({
            url: this.action,
            type: this.method,
            data: $(this).serialize(),
            success: function (result) {
                if (result.success) { 
                    // We have a JSON object in case of success
                    alert('success');
                } else {
                    // We have the partial with errors in case of failure
                    // so all we have to do is update the DOM
                    $('#myform').html(result);
                }
            }
        });
        return false;
    });
});
51
Darin Dimitrov

ModelStateエラーを返す可能性があります。これはテストされていませんが、このようなものは機能するはずです。

return Json(new
            {
                success = false,
                errors = ModelState.Keys.SelectMany(k => ModelState[k].Errors)
                                .Select(m => m.ErrorMessage).ToArray()
            });

編集:ビューにエラーを表示するには、成功したかどうかを確認し、成功しなかった場合は、エラーのリストを繰り返し処理して、エラーが表示されている場所に配置します。

if(!result.success) {
    for(var error in result.errors) {
        $('#errorMessages').append(error + '<br />');
    }
}

ほとんどのプロジェクトでDarinの回答を好みますが、コンシューマーが必ずしも独自のアプリケーションであるとは限りません。その場合、コンシューマーが必要に応じてエラーを表示できるため、エラーのリストを返す方が適切です。

15

個々のプロパティのModelStateエラーを表すクラスを作成します。

public class ValidationError
{

    public string PropertyName = "";
    public string[] ErrorList = null;
}

ModelStateに基づいてValidationErrorsのリストを返すメソッドを作成します

    public IEnumerable<ValidationError> GetModelStateErrors(ModelStateDictionary modelState)
    {
        var errors = (from m in modelState
                            where m.Value.Errors.Count() > 0
                            select
                               new ValidationError
                               {
                                   PropertyName = m.Key,
                                   ErrorList = (from msg in m.Value.Errors
                                                  select msg.ErrorMessage).ToArray()
                               })
                            .AsEnumerable();
        return errors;
    }

次に、コントローラーでPostメソッドを実行します。

        if (!ModelState.IsValid)
        {
            return Json(new
            {
                errors = true,
                errorList = GetModelStateErrors(ModelState)
            }, JsonRequestBehavior.AllowGet);
        }

上記で返されたエラーリストをループするJS関数を作成できます

$.ajax({
            cache: false,
            async: true,
            type: "POST",
            url: form.attr('action'),
            data: form.serialize(),
            success: function (data) {
                if (data.errors) {
                    displayValidationErrors(data.errorList);
                 }
            },
        error: function (result) {
            console.log("Error");
        }

    });

function displayValidationErrors(errors) {
    $.each(errors, function (idx, validationError) {

        $("span[data-valmsg-for='" + validationError.PropertyName + "']").text(validationError. ErrorList[0]);

    });
}

上記の例では、「ErrorList」から最初のエラーメッセージのみを取得しています。追加のループを作成して、すべてのメッセージを取得し、検証スパンに追加できます。

1
Asaad

このコードを試してください。これはあなたの問題に対する簡単な解決策です。すべてのモデル状態エラーを1つの文字列に結合します。

[HttpPost]
    public ActionResult SaveCustomer(CustomerViewModel input) {
        if (!ModelState.IsValid) { // <-- business validation
            return Json(new { success = false, errors = string.Join("; ", ModelState.Values
                                            .SelectMany(x => x.Errors)
                                            .Select(x => x.ErrorMessage));});
        }
        // persist 
        return Json(new { success = true });
    }
0
Keerthi