为各种模型动态创建隐藏的表单字段(MVC 4)

Dynamically creating hidden form fields for various models (MVC 4)

本文关键字:字段 表单 MVC 隐藏 模型 动态 创建      更新时间:2023-09-26

我试图为一组属性动态创建隐藏字段,但在提交表单时遇到了500服务器错误。我确认了以下内容:

  • 我在foreach语句中迭代的属性是正确的
  • property.Name是NewItem.GetType()检索到的类型的有效属性名称

这是我的:

查看

@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; }
}

控制器

[HttpPost]
public ActionResult AddItem([Bind(Prefix = "NewItem")] ItemViewModel model)
{
    // Stuff here.
}

值得注意的是,以下操作会在生成的HTML中生成具有正确名称和值的隐藏字段,但隐藏字段的值不会发布到控制器操作:

@foreach (var property in Model.NewItem.GetType().GetProperties().Where(<criteria here>))
{
    @Html.Hidden(property.Name, column.GetValue(Model.NewItem, null))
}

因此,问题似乎出在m => m.NewItem.GetType().GetProperty(property.Name)组件

  1. 这种类型的逻辑不属于视图
  2. Html.HiddenFor()期望表达式(Expression<Func<TModel, TProperty>>)作为第一个参数,但.GetProperty()返回PropertyInfo类型
  3. 您不应该为属性生成多个隐藏输入而是使用视图模型来只表示您需要进行编辑(它通过向客户,然后将其再次张贴回,保持不变,以及任何人可以使用FireBug或类似工具来更改值也许一点也不明智

但是,如果您确实想这样做,您可以创建一个html帮助程序,为所有用[HiddenInput]属性标记的属性生成隐藏输入(或者修改此示例以在某些条件下通过,过滤所需属性)

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());
}

注意,这也会生成iddata-val-*属性,这可能是不必要的,因此您可以通过使用来最小化生成的html

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());
}