Reputation: 340
I have a form that contains 3 distinct sections that looks something like this:
<form action="/Submit/" method="POST">
<h2>
Your Info:
</h2>
<ul>
<li>
<label>
First Name:
@Html.TextBoxFor(m => m.FirstName)
</label>
</li>
<li>
<label>
Last Name:
@Html.TextBoxFor(m => m.LastName)
</label>
</li>
</ul>
<h2>
Membership:
</h2>
<ul>
<li>
<label>@Html.RadioButtonFor(m => m.MembershipLength_Months, 3) 3 Months</label>
</li>
<li>
<label>@Html.RadioButtonFor(m => m.MembershipLength_Months, 12) 12 Months</label>
</li>
</ul>
<h2>
Billing Info:
</h2>
@Html.EditorFor(m=> m.PaymentInfo)
<input type="submit" value="Submit" />
</form>
What I'd like to do is to have a summary per section. I know I could do something like this under each H2:
@if (ViewData.ModelState.Keys.Contains("FirstName") || ViewData.ModelState.Keys.Contains("LastName"))
{
<div>
summary text
@Html.ValidationMessageFor(m => m.FirstName)
@Html.ValidationMessageFor(m => m.LastName)
</div>
}
But it feels like there should be a cleaner solution. Google has completely failed me and I haven't been able to find a custom helper or validation summary extension that takes a collection to represent the properties to summarize.
Each of the sections contains a good number of fields so the ModelState.Keys comparison gets pretty ugly pretty quickly. Is there a clean way to do this?
Upvotes: 6
Views: 261
Reputation: 1038930
But it feels like there should be a cleaner solution.
Yes, you could write a custom, reusable HTML helper to achieve this task:
public static class HtmlExtensions
{
public static IHtmlString Summary<TModel>(
this HtmlHelper<TModel> html,
params Expression<Func<TModel, object>>[] expressions
)
{
var div = new TagBuilder("div");
var sb = new StringBuilder();
foreach (var expression in expressions)
{
var unary = expression.Body as UnaryExpression;
if (unary != null && unary.NodeType == ExpressionType.Convert)
{
var lambda = Expression.Lambda(unary.Operand, expression.Parameters);
sb.AppendLine(html.ValidationMessage(ExpressionHelper.GetExpressionText(lambda)).ToHtmlString());
}
else
{
sb.AppendLine(html.ValidationMessageFor(expression).ToHtmlString());
}
}
div.InnerHtml = sb.ToString();
return new HtmlString(div.ToString());
}
}
which could be used like that:
<h2>
Your Info:
@Html.Summary(
x => x.FirstName,
x => x.LastName
)
</h2>
The helper allows you to list any properties you want to be included in the summary as validation errors.
Upvotes: 4