Ajax.BeginForm and validation
Client side validation doesn't work for me in Ajax.BeginForm
This is my code:
<div id="report"> <div id="projectReport"> <div > @{ Html.EnableClientValidation(); } @using (Ajax.BeginForm("AnalyticsDates", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "reportContent" })) { @Html.LabelFor(m => m.StartDate) @Html.TextBoxFor(m => m.StartDate, new { id = "start" }) @Html.ValidationMessageFor(model => model.StartDate) @Html.LabelFor(m => m.EndDate) @Html.TextBoxFor(m => m.EndDate, new { id = "end" }) @Html.ValidationMessageFor(model => model.EndDate) <input id="btnsearch" type="submit" value=@Titles.Search class="iconHeader"/> } </div> </div> <div id="reportContent"> </div> </div> And I turned on the verification on the web.config page:
<add key="ClientValidationEnabled" value="true" /> <add key="UnobtrusiveJavaScriptEnabled" value="true" /> and js files are added as well
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script> the second problem is related to the first, my action
[HttpPost] [Authorize(Roles = "XXXReport")] public async Task<ActionResult> AnalyticsDates(ReportRequestVM reportRequestVM) { if (!ModelState.IsValid) { return View("**MainReports**", reportRequestVM); } // fill reportRequestVM with data return View("**PartialReport**", reportRequestVM); } If the model is correct, I return a partial view, and the page looks fine, otherwise I return the main view with the form, but this page displays it twice. the question is, in case of unsuccessful client validation, how to return the main form with validation errors?
Any help would be appreciated, 10x Rony
I figured this out ... you should have a partial view of the result and query.
and on failure, you should return "http bad request" and use the following to set the validation in the partial search view.
this is how it should look:
@using (Ajax.BeginForm("CloudAnalyticsDates", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "reportContent", OnFailure = "OnCloudAnalyticsFailure", OnBegin = "ValidateForm", })) { @Html.LabelFor(m => m.StartDate) @Html.TextBoxFor(m => m.StartDate, new { id = "start" }) @Html.ValidationMessageFor(model => model.StartDate) @Html.LabelFor(m => m.EndDate) @Html.TextBoxFor(m => m.EndDate, new { id = "end" }) @Html.ValidationMessageFor(model => model.EndDate) <input id="btnsearch" type="submit" value=@Titles.Search class="iconHeader"/> } </div> </div> <script type="text/javascript"> $(document).ready(function () { $("#datePicker").kendoDatePicker(); $("#start").kendoDatePicker().data("kendoDatePicker"); $("#end").kendoDatePicker().data("kendoDatePicker"); }); function OnCloudAnalyticsFailure(parameters) { $('#projectReport').html(parameters.responseText); $('#reportContent').empty(); CleanValidationError('form'); } </script> and on the server it should look like this:
[HttpPost] public async Task<ActionResult> CloudAnalyticsDates(ReportRequestVM reportRequestVM) { if (!ModelState.IsValid) { Response.StatusCode = (int)HttpStatusCode.BadRequest; return PartialView("_ReportQuery", reportRequestVM); } reportRequestVM.BomTotals = await CommonRequestsHelper.GetBomTotalAnalytics(bomTotalRequest); return PartialView("_ProjectReport", reportRequestVM); } If your model state is invalid and you return a view with a model containing errors, the response sent by the server has an http status of 200, indicating that the request has been completed. In this case, the ajax form does what you instructed it to insert the returned response into the repostContent of the separation (you can make sure that by checking that the second page is being rendered inside this div). As for how to get the ajax submission form to act like a regular form submission while validation messages are displayed, I have not found a simple direct translation method (maybe someone can specify one here :) for us). I solved this:
- The presence of the form in the partial view displayed in the main form div (formDiv).
- Having "OnFailure" specified in ajax form that inserts the response text into a div containing the original form (formDiv)
- Override OnActionExecuted (since I have a main controller, which all my others inherit from this, runs in only one place) to check if the IsAjax and ModelState request are invalid, I change the response status to 4xx. This causes OnFailure to start, replacing the original form with the one that returns inside the If (! ModelState.Isvalid) branch.