Reputation: 3003
I'm trying to dynamically create hidden fields for a set of properties, but I'm getting a 500 server error when I submit the form. I confirmed the following:
Here's what I have:
View
@model PaneViewModel
using (Ajax.BeginForm("AddItem", "Action", new AjaxOptions
{
UpdateTargetId = "tool-wrapper",
HttpMethod = "POST",
}))
{
// Some standard input fields here (these are working properly).
[...]
// Here's what's broken:
@foreach (var property in Model.NewItem.GetType().GetProperties().Where(<criteria here>))
{
@Html.HiddenFor(m => m.NewItem.GetType().GetProperty(property.Name), column.GetValue(Model.NewItem, null))
}
<button type="submit">Add</button>
}
ItemViewModel
public class ItemViewModel
{
public int SomeField { get; set; }
public int AnotherField { get; set; }
}
PaneViewModel
public class PaneViewModel
{
public ItemViewModel NewItem { get; set; }
}
Controller
[HttpPost]
public ActionResult AddItem([Bind(Prefix = "NewItem")] ItemViewModel model)
{
// Stuff here.
}
It's worth noting that the following generates the hidden fields with the correct names and values in the generated HTML, but the values of the hidden field aren't posted to the controller action:
@foreach (var property in Model.NewItem.GetType().GetProperties().Where(<criteria here>))
{
@Html.Hidden(property.Name, column.GetValue(Model.NewItem, null))
}
So it seems the problem is with the m => m.NewItem.GetType().GetProperty(property.Name)
component
Upvotes: 1
Views: 2196
Reputation:
Html.HiddenFor()
expects an expression (Expression<Func<TModel,
TProperty>>
) as the first parameter, but .GetProperty()
returns
typeof PropertyInfo
However, if you do want to do this, the you could create a html helper that generates hidden inputs for all properties marked with the [HiddenInput]
attribute (or modify this example to pass in some condition that filters the required properties)
public static MvcHtmlString HiddenForModel<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
{
StringBuilder html = new StringBuilder();
ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
var properties = metaData.Properties.Where(p => p.TemplateHint == "HiddenInput");
foreach(var property in properties)
{
html.Append(helper.Hidden(property.PropertyName));
}
return MvcHtmlString.Create(html.ToString());
}
Note this will also generate the id
and data-val-*
attributes which are probably unnecessary, so you could minimize the generated html by using
foreach(var property in properties)
{
TagBuilder input = new TagBuilder("input");
input.MergeAttribute("type", "hidden");
input.MergeAttribute("name", property.PropertyName);
input.MergeAttribute("value", string.Format("{0}", property.Model));
html.Append(input.ToString());
}
Upvotes: 2