Reputation: 6477
I have a nested Model ie:
MySuperClass
ConfigClass
DataClass
I pass "MySuperClass" to the View which contains Form. Elements on this form use LINQ to do the model binding, ie:
EditorFor(model=>model.DataClass.Name)
EditorFor(model=>model.DataClass.DateOfBirth)
I use MySuperClass.ConfigClass properties in the View.
I have Validation DataAnnotations on the DataClass properties such as "Required".
I return back to my form handler in the controller:
[HttpPost]
public ActionResult Index(MySuperClass mySC, string unused = "")
//ModelState not firing.... on empty required columns
if (ModelState.IsValid))
I quess "mySuperClass" is like a ViewModel.
How can I get the Validation to work?
EDIT
Also using using the Validation Helper:
@Html.EditorFor(model=>model.DataClass.Name)
@Html.ValidationMessageFor(model => model.DataClass.Name)
Upvotes: 1
Views: 4502
Reputation: 1547
The nested models should work in MVC 3. Please try with this sample.
public class HomeController : Controller
{
public ActionResult IndexNew()
{
Sample obj = new Sample() {MyTest=new Test() };
return View(obj);
}
[HttpPost]
public ActionResult IndexNew(Sample test)
{
return View(test);
}
}
public class Sample
{
public Test MyTest { get; set; }
}
public class Test
{
[Required]
public string Name { get; set; }
}
@model MvcApplication2.Controllers.Sample
@{
ViewBag.Title = "IndexNew";
}
<h2>IndexNew</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Sample</legend>
@Html.TextBoxFor(e => e.MyTest.Name);
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
Upvotes: 1
Reputation: 834
I solved the same trouble as yours in one of my project like this, you need to create filter and use it in both sending from action to view and also posting from view to action(Post action):
public abstract class ModelStateBase : ActionFilterAttribute
{
protected static readonly string Key = typeof(ModelStateBase).FullName;
}
public class OnGetMetaData : ModelStateBase
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (!filterContext.Controller.ViewData.ModelState.IsValid)
{
if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
{
filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
}
}
base.OnActionExecuted(filterContext);
}
}
public class OnPostMetaData : ModelStateBase
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;
if (modelState != null)
{
if (filterContext.Result is ViewResult)
{
filterContext.Controller.ViewData.ModelState.Merge(modelState);
}
else
{
filterContext.Controller.TempData.Remove(Key);
}
}
base.OnActionExecuted(filterContext);
}
}
and in the get and post action you can act like this:
[OnPostMetaData]
public ActionResult Index()
{
return View();
}
[HttpPost, OnGetMetaData]
public ActionResult Index(MySuperClass mySuperClass)
{
if (ModelState.IsValid)
{
//do something
}
return View();
}
and finally the view is the same as regular form as you have used.
Upvotes: 1
Reputation: 239430
Nested objects will be validated, as long as they are not null, so you just need to ensure that Model.DataClass
is an instance of DataClass
and not null. The easiest way to do that is in the constructor of MySuperClass
:
public MySuperClass()
{
DataClass = new DataClass();
}
Upvotes: 1