I'm using MVC 4 and Entity Framework to develop a web app. I'm working with partial views which are loaded with javascript. One of them is a create view which includes validation. And that's my problem : the validation. I have a custom validation logic and, for example, if a user enters some numbers into a field such as "Name", it displays an error.
Here, with the partial views, it redirects me on my partial with the errors displayed but what I wanted to do is to stay on my main view (Index view) and keep my partial view which displays the errors.
EDIT :
Here is my partial view :
@model BuSIMaterial.Models.Person
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Person</legend>
<div class="editor-label">
First name :
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.FirstName, new { maxlength = 50 })
@Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
Last name :
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.LastName, new { maxlength = 50 })
@Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
National number :
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.NumNat, new { maxlength = 11 })
@Html.ValidationMessageFor(model => model.NumNat)
</div>
<div class="editor-label">
Start date :
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.StartDate, new {@class = "datepicker", @placeholder="yyyy/mm/dd"})
@Html.ValidationMessageFor(model => model.StartDate)
</div>
<div class="editor-label">
End date :
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.EndDate, new { @class = "datepicker", @placeholder = "yyyy/mm/dd" })
@Html.ValidationMessageFor(model => model.EndDate)
</div>
<div class="editor-label">
Distance House - Work (km) :
</div>
<div class="editor-field">
@Html.EditorFor(model => model.HouseToWorkKilometers)
@Html.ValidationMessageFor(model => model.HouseToWorkKilometers)
</div>
<div class="editor-label">
Category :
</div>
<div class="editor-field">
@Html.DropDownList("Id_ProductPackageCategory", "Choose one ...")
@Html.ValidationMessageFor(model => model.Id_ProductPackageCategory) <a href = "../ProductPackageCategory/Create">Add a new category?</a>
</div>
<div class="editor-label">
Upgrade? :
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Upgrade)
@Html.ValidationMessageFor(model => model.Upgrade)
</div>
<br />
<div class="form-actions">
<button type="submit" class="btn btn-primary">Create</button>
</div>
</fieldset>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/bundles/jqueryui")
@Styles.Render("~/Content/themes/base/css")
}
In my view Index, I have this :
<div class="form-actions"><button type="button" id="create" class="btn btn-primary">Create</button> </div>
<div id ="create_person"></div>
And the way I load my Partial View :
$("#create").click(function () {
var form = $("#create_person").closest("form");
form.removeData('validator');
form.removeData('unobtrusiveValidation');
$.validator.unobtrusive.parse(form);
$.ajax({
url: "/Person/CreateOrUpdate",
type: "POST",
data: $("#create_person").serialize(),
cache: false
});
// var url = '/Person/CreatePerson';
// $("#create_person").load(url);
});
The actions :
[HttpGet]
public ActionResult CreateOrUpdate()
{
ViewBag.Id_ProductPackageCategory = new SelectList(db.ProductPackageCategories, "Id_ProductPackageCategory", "Name");
return View();
}
[HttpPost]
public JsonResult CreateOrUpdate(Person person)
{
ViewBag.Id_ProductPackageCategory = new SelectList(db.ProductPackageCategories, "Id_ProductPackageCategory", "Name", person.Id_ProductPackageCategory);
try
{
if (!ModelState.IsValid)
{
string messages = string.Join("; ", ModelState.Values
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
throw new Exception("Please correct the following errors: " + Environment.NewLine + messages);
}
db.Persons.AddObject(person);
db.SaveChanges();
return Json(new { Result = "OK" });
}
catch (Exception ex)
{
return Json(new { Result = "ERROR", Message = ex.Message });
}
}
If you post the page it will not come back to the dynamically loaded partial view. Try to make a ajax call to /Person/CreatePerson. Your CreatePerson will look similar to
`
Besides unobtrusive validation will not work easily with dynamic content. check the link unobtrusive validation on dynamically added partial view (not working)
I came across this scenario whereby my main View uses Ajax posts to retrieve PartialViews and delivers the markup of the PartialView into my View. I use the jQuery validation framework to implement client side unobtrusive validation. When I tried to validate my form that had been loaded into the page via an Ajax call, the validation did not appear to be working, my form simply posted. As it turns out, the unobtrusive jQuery validator library parses the markup of a page after it has finished loading for all the validation rules on the page. The result is, jQuery doesn’t know that the dynamically added markup has any validation rules resulting in no validation errors being thrown on post.
Solution
Traffy there is a method that is publicly accessible in the unobtrusive jQuery library which you can call, which will force the parser to scan the markup you just loaded. To do this you need to add the following code to the PartialView (or other dynamically loaded content)
Then in your parent page you can handle the form submission and check the form is valid like this;
And that is it!! (Credit: Dave's coding)
I've developed a decent workaround for this. The partial page won't show the server errors on postback. First of all, we get the errors, send them back to the page, then create them in javascript & revalidate the page. Hopefully, hey presto!
In your controller:
I put it in TempData so it can be retrieve easily from the partial. Yes, I called it shepherdErrors, it's my idea so I can call the concept whatever silly name I want! Shepherd the error codes to where they should be or something being the general idea.
In a helper class:
Then on the html page somewhere after jquery being loaded:
This should work out of the box with general MVC development provided text boxes that are generated are based on the variable names - this is default behaviour of MVC.