Search code examples
ajaxasp.net-mvc-3layoutrazorvalidationerror

How to update DIV in _Layout.cshtml with message after Ajax form is submitted?


Currently I have a Razor View like this:

TotalPaymentsByMonthYear.cshtml

@model MyApp.Web.ViewModels.MyViewModel

@using (@Ajax.BeginForm("TotalPaymentsByMonthYear",
        new { reportName = "CreateTotalPaymentsByMonthYearChart" },
        new AjaxOptions { UpdateTargetId = "chartimage"}))
{    
    <div class="report">

    // MyViewModel fields and validation messages...

    <input type="submit" value="Generate" />

    </div>
}

<div id="chartimage">
@Html.Partial("ValidationSummary")
</div>

I then display a PartialView that has a @Html.ValidationSummary() in case of validation errors.

ReportController.cs

public PartialViewResult TotalPaymentsByMonthYear(MyViewModel model,
       string reportName)
{
    if (!ModelState.IsValid)
    {
        return PartialView("ValidationSummary", model);
    }

    model.ReportName = reportName;

    return PartialView("Chart", model);
}

What I'd like to do is: instead of displaying validation errors within this PartialView, I'm looking for a way of sending this validation error message to a DIV element that I have defined within the _Layout.cshtml file.

_Layout.cshtml

<div id="message">

</div>

@RenderBody()

I'd like to fill the content of this DIV asynchronously. Is this possible? How can I do that?


Solution

  • Personally I would throw Ajax.* helpers away and do it like this:

    @model MyApp.Web.ViewModels.MyViewModel
    
    <div id="message"></div>
    
    @using (Html.BeginForm("TotalPaymentsByMonthYear", new { reportName = "CreateTotalPaymentsByMonthYearChart" }))
    {
        ...
    }
    
    <div id="chartimage">
        @Html.Partial("ValidationSummary")
    </div>
    

    Then I would use a custom HTTP response header to indicate that an error occurred:

    public ActionResult TotalPaymentsByMonthYear(
        MyViewModel model,
        string reportName
    )
    {
        if (!ModelState.IsValid)
        {
            Response.AppendHeader("error", "true");
            return PartialView("ValidationSummary", model);
        }
        model.ReportName = reportName;
        return PartialView("Chart", model);
    }
    

    and finally in a separate javascript file I would unobtrusively AJAXify this form and in the success callback based on the presence of this custom HTTP header I would inject the result in one part or another:

    $('form').submit(function () {
        $.ajax({
            url: this.action,
            type: this.method,
            data: $(this).serialize(),
            success: function (result, textStatus, jqXHR) {
                var error = jqXHR.getResponseHeader('error');
                if (error != null) {
                    $('#message').html(result);
                } else {
                    $('#chartimage').html(result);
                }
            }
        });
        return false;
    });