I have a model that has this form:
public class GlobalSettingsViewModel { public List<SettingViewModel> Settings{ get;set;} } public class SettingViewModel { public string Name{ get;set;} [Range(0,100)] public decimal SettingValue{ get;set;} }
My view calls Html.RenderPartial("SettingView") for each SettingViewModel parameter.
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SettingViewModel>" %> <% using (Html.BeginForm("Save", "GlobalSettings", FormMethod.Post)) { %> <table> <tr> <td width="150px"> <%= Html.DisplayFor(m=>m.Name) %> </td> <td> <%= Html.TextBoxFor(m=>m.SettingValue) %> </td> <td> <input type="submit" value="Save" class="uiButton" /> <%=Html.ValidationMessageFor(m=>m.SettingValue) %> </td> </tr> </table> <%} %>
Each SettingView displays a form that returns to the Save action.
SettingViewModel correctly rehydrated from the form, and validation determines when an out or range value is generated.
I returned the original Index view with the full GlobalSettingsViewModel that it requires.
However, when the page displays each Validator for SettingValue shows this error message instead of the text field with the wrong value?
What is the correct way to do server side validation on PartialView when it is a page of a collection of items?
UPDATE
So, here's what I have .... seems a little strange, but it seems to work.
I can save one setting at a time and show validation errors when they occur. But the strange way that I preserve using the partial model seems a little strange.
index.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/MVC.Master" Inherits="System.Web.Mvc.ViewPage<GlobalSettingsViewModel>" %> <fieldset style="margin: 5px; width: 350px;"> <legend>Global System Settings</legend> <div> <%= Html.EditorFor(m => Model.Settings)%> </div> </fieldset>
SettingViewModel.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SettingViewModel>" %> <% using (Html.BeginForm("Save", "GlobalSettings", FormMethod.Post)) { %> <table> <tr> <td width="150px"> <%= Model.Name %> </td> <td> <%= Html.TextBoxFor(m => m.SettingValue) %> </td> <td> <input type="submit" value="Save" class="uiButton" /> </td> </tr> <tr> <td colspan="3"> <%=Html.ValidationMessageFor(m=>m.SettingValue) %> </td> </tr> </table> <%= Html.HiddenFor(m => m.SettingName)%> <%= Html.HiddenFor(m => m.Name)%> <%} %>
GlobalSettingsController.cs
public ActionResult Index() { var settings = GetSettings(); if (TempData["Message"] != null) { settings.Message = TempData["Message"].ToString(); settings.HasMessage = true; } return View(settings); } [AuthorizationFilter(true, null)] [HttpPost] public ActionResult Save(GlobalSettingsViewModel model) { if (ModelState.IsValid) { GlobalSettings.SetGlobalSetting(model.Settings[0].SettingName, model.Settings[0].SettingValue); TempData["Message"] = "Saved " + model.Settings[0].Name; return RedirectToAction("Index"); } var settings = GetSettings(); return View("Index", settings); }