Validation Summary for Collections

asp.net-mvc, asp.net-mvc-2, validationsummary

Solution

You are going to have to extend the HtmlHelper methods and roll your own. Heres the bit of code that is important for your situation where you need a group by:

//HtmlHelper being extended
if(helper.ViewData.ModelState.IsValid)
{
    foreach(KeyValuePair<string,ModelState> keyPair in helper.ViewData.ModelState)
    {     
        //add division for group by here using keyPair.Key property (would be named "Person" in your case).

        foreach(ModelError error in keyPair.Value.Errors)
        {
            //now add message using error.ErrorMessage property
        }
    }
}

Problem

EDIT: upgraded this question to MVC 2.0 With asp.net MVC 2.0 is there an existing method of creating Validation Summary that makes sense for models containing collections? If not I can create my own validation summary Example Model: ``` public class GroupDetailsViewModel { public string GroupName { get; set; } public int NumberOfPeople { get; set; } public List<Person> People{ get; set; } } public class Person { [Required(ErrorMessage = "Please enter your Email Address")] [RegularExpression(@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$", ErrorMessage = "Please enter a valid Email Address")] public string EmailAddress { get; set; } [Required(ErrorMessage = "Please enter your Phone Number")] public string Phone { get; set; } [Required(ErrorMessage = "Please enter your First Name")] public string FirstName { get; set; } [Required(ErrorMessage = "Please enter your Last Name")] public string LastName { get; set; } } ``` The existing summary `<%=Html.ValidationSummary %>` if nothing is entered looks like this. The following error(s) must be corrected before proceeding to the next step * Please enter your Email Address * Please enter your Phone Number * Please enter your First Name * Please enter your Last Name * Please enter your Email Address * Please enter your Phone Number * Please enter your First Name * Please enter your Last Name The design calls for headings to be inserted like this: The following error(s) must be corrected before proceeding to the next step Person 1 * Please enter your Email Address * Please enter your Phone Number * Please enter your First Name * Please enter your Last Name Person 2 * Please enter your Email Address * Please enter your Phone Number * Please enter your First Name * Please enter your Last Name Answer Based on Pharcyde's answer. ``` public static MvcHtmlString NestedValidationSummary(this HtmlHelper helper) { if (helper.ViewData.ModelState.IsValid) return MvcHtmlString.Empty; // create datastructure to group error messages under a given key (blank key is for general errors) var errors = new Dictionary<string,List<string>>(); foreach (KeyValuePair<string, ModelState> keyPair in helper.ViewData.ModelState) { foreach (ModelError error in keyPair.Value.Errors) { //determine the 'key' for the group in which this error belongs var key = keyPair.Key.Split(']')[0]; if (key.Contains("People[")) key = "Person " + key.Split('[')[1]; else key = string.Empty; if(!errors.ContainsKey(key)) errors.Add(key,new List<string>()); //now add message using error.ErrorMessage property errors[key].Add(error.ErrorMessage); } } // generate the HTML var ul = new TagBuilder("ul"); foreach (KeyValuePair<string, List<string>> errorPair in errors.OrderBy(p=>p.Key)) { var li = new TagBuilder("li"); if(!string.IsNullOrEmpty(errorPair.Key)) li.InnerHtml += string.Format("<p class=\"no-bottom-margin\"><strong>{0}</strong></p>",errorPair.Key); var innerUl = new TagBuilder("ul"); foreach (var message in errorPair.Value) { var innerLi = new TagBuilder("li"); innerLi.InnerHtml = message; innerUl.InnerHtml += innerLi.ToString(TagRenderMode.Normal); } li.InnerHtml += innerUl.ToString(TagRenderMode.Normal); ul.InnerHtml += li.ToString(TagRenderMode.Normal); } return MvcHtmlString.Create(ul.ToString(TagRenderMode.Normal)); } ```

Original source