简体   繁体   中英

MVC AJAX Return View if server-side validation fails

I have a search form, which will do some client side validation, call the server action, do some server side validation, and then return either the original view (with the modelstate errors) OR the search results.

For this approach to work, i would need to render the view to a string, and return a Json result. I could probably do that with one of the answers in this question: Render a view as a string

However, if i'm having to implement my own 'RenderView' type function, is this really the best way to do this? Or is there a better design decision for implementing this kind of functionality? Any help would be greatly appreciated.

An abstraction of the code is listed below for reference;

Controller:

public ActionResult Index()
{
    return View(new SearchModel());
}

public ActionResult Search(SearchModel criteria)
{
    if (!ModelState.IsValid)
        return Json(new { HasErrors = true, Result = RenderViewToString("Index", criteria) });

    var results = {Do Search...};
    return PartialView("SearchResults", results);
}

View:

@using(Html.BeginForm(...))
{
    {form fields...}
    {submit button...}
}
<div id="search-results"></div>

<script type="text/javascript">
    $(document).on("submit", "form", function(e) {
        if (!$(this).valid()) return false;

        e.preventDefault(); // Submit the form with ajax instead.
        $.ajax({
            url: this.action,
            type: this.method
            data: $(this).serialize(),
            success: function(data) {
                if (data.HasErrors) {
                    $(document).html(data.Result);
                }
                else {
                    $("#search-results").html(data);
                }
            }
        });
     });
</script>

First of all you need this jquery function to add error in validation summary

$.fn.addNewErrorMessage = function (message) {
    $(this).find('.validation-summary-valid').removeClass('validation-summary-valid')
        .addClass('validation-summary-errors');
    $(this).find(".validation-summary-errors ul").append("<li>" + message + "</li>");
}

Then you need make a list of error and return it as a JSON format like this code in action.

if (!modelState.IsValid)
{
    var errors = ModelState.ToDictionary(kvp => kvp.Key,
           kvp => kvp.Value.Errors
                      .Select(e => e.ErrorMessage).ToArray())
                      .Where(m => m.Value.Count() > 0);
     return Json(new {HasErrors = true,Errors = errors});
}

After that in success function in ajax use addNewErrorMessage function to show error messages

$.ajax({
        url: this.action,
        type: this.method
        data: $(this).serialize(),
        success: function(data) {
            if (data.HasErrors) {
                for(int i; i<data.Errors.length)
                {
                    $('form').addNewErrorMessage(data.Errors[i].Value);
                }
            }
            else {
                $("#search-results").html(data);
            }
        }

I've marked Kiyarash's answer as correct, as it put me on the right track. Here is what i actually used though: (Please note that this will only show the last error for each field - I will be adding some logic into it, so that it shows multiple error messages).

if (!ModelState.IsValid)
{
    return Json(new
    {
        HasErrors = true,
        Errors = ModelState.ToDictionary(
            ms => ms.Key,
            ms => ms.Value.Errors.Select(e => e.ErrorMessage).ToArray()
        ).Where(ms => ms.Value.Count() > 0)
    }, JsonRequestBehavior.AllowGet);
}

$.ajax({
    ...
    success: function(data) {
        if (data.HasErrors) {
            showErrorMessages(data.Errors, $("form"));
        }
        else {
            $("#search-results").html(data);
        }
    }
});

function showErrorMessages(errors, context) {
    $.each(errors, function (i, error) {
        $("[data-valmsg-for='" + error.Key + "']", context).text(error.Value)
            .removeClass("field-validation-valid")
            .addClass("field-validation-error");
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM