@Html.HiddenFor 不适用于 ASP.NET MVC 中的列表
Posted
技术标签:
【中文标题】@Html.HiddenFor 不适用于 ASP.NET MVC 中的列表【英文标题】:@Html.HiddenFor does not work on Lists in ASP.NET MVC 【发布时间】:2012-03-12 05:16:06 【问题描述】:我正在使用一个包含 List 作为属性的模型。我正在使用从 SQL Server 获取的项目填充此列表。我希望列表隐藏在视图中并传递给 POST 操作。稍后我可能想使用 jQuery 向此列表添加更多项目,这使得数组不适合以后扩展。通常你会使用
@html.HiddenFor(model => model.MyList)
为了完成这个功能,但由于某种原因,POST 中的 List 始终为空。
很简单的问题,有人知道MVC为什么会这样吗?
【问题讨论】:
通常你不会像这样隐藏整个列表。就<input />
s 而言,您想要的输出是什么?
MyList
包含什么? HiddenFor
一次只用于一个输入。
Model.MyList
是什么类型?您可能需要手动对列表执行一些序列化/反序列化。
[***.com/questions/4381871/…类似问题。
类似问题:Use of HiddenFor with intellisense
【参考方案1】:
我刚刚遇到这个问题,只需执行以下操作即可解决:
@for(int i = 0; i < Model.ToGroups.Count; i++)
@Html.HiddenFor(model => Model.ToGroups[i])
通过使用for
而不是foreach
,模型绑定将正常工作并拾取列表中的所有隐藏值。似乎是解决此问题的最简单方法。
【讨论】:
谢谢!拯救了我的夜晚。 谢谢 - 不错的简单解决方案。不过只需要一个小模块:需要引用对象的 Id 字段。所以如果该字段被称为 RowId,那么:@Html.HiddenFor(model => Model.ToGroups[i].RowId)
为我工作,即使我在集合中的模型上有多个字段时也是如此。 IE。 @Html.EditorFor(model => Model.ToGroups[i].Id)
下一次是 @Html.EditorFor(model => Model.ToGroups[i].Description)
- 都在 for 循环中。控制器能够将其映射到具有这些字段的模型列表。为了确保它没有出现在屏幕上,只需将其包围在<div style="display: none;"></div>
@user3186023 在这里回答一个非常老的评论,但也许其他人会遇到同样的问题:将for
-loop 更改为:for(int i = 0; i < Model.Departments.Count(); i++)
我正在努力将一个列表正确绑定到视图中,但没有任何结果起作用(而且我还是个谷歌谷歌用户)。这种SO的帖子字面上拯救了人们。精确+简洁!!!【参考方案2】:
HiddenFor 不像 DisplayFor 或 EditorFor。它不适用于集合,只能用于单个值。
您可以使用 MVC Futures 项目中提供的 Serialize HTML 帮助器将对象序列化为隐藏字段,或者您必须自己编写代码。更好的解决方案是简单地序列化某种 ID 并在回发时从数据库中重新获取数据。
【讨论】:
你有例子吗?我试过这个,提交表单时它无法绑定到 ViewModel 值。 @AlanMacdonald - 如果绑定失败,那是因为您的命名不正确,很可能是因为您使用了 foreach 而不是 for 和索引器。或者,也许您没有在绑定中使用正确的属性。见weblogs.asp.net/shijuvarghese/archive/2010/03/06/… 谢谢。实际上,当我尝试时,它实际上是 @Html.Serialize("Model.ModelIDs", Model.ModelIDs) 其中 Model 是我的 ViewModel 并且它具有 ModelIDs int 数组属性。所以没有循环或任何东西。提交表单时,ModelID 在绑定的 ViewModel 中始终为 null。 @AlanMacdonald - 您没有在名称中包含“模型”。【参考方案3】:这有点小技巧,但如果 @Html.EditorFor
或 @Html.DisplayFor
为您的列表工作,如果您想确保它在发布请求中发送但不可见,您可以将其样式设置为使用 display: none;
改为隐藏它,例如:
<div style="display: none;">@Html.EditorFor(model => model.MyList)</div>
【讨论】:
这不会在请求发布时保存模型中的值。 如果 .EditorFor 设置为正常工作,那么我相信这也应该工作。【参考方案4】:如何使用 Newtonsoft 将对象反序列化为 json 字符串,然后将其插入到您的隐藏字段中,例如 (Model.DataResponse.Entity.Commission 是一个简单的 "CommissionRange" 对象的List,您将在 JSON 中看到)
@using (Ajax.BeginForm("Settings", "AffiliateProgram", Model.DataResponse, new AjaxOptions UpdateTargetId = "result" ))
string commissionJson = JsonConvert.SerializeObject(Model.DataResponse.Entity.Commission);
@Html.HiddenFor(data => data.DataResponse.Entity.Guid)
@Html.Hidden("DataResponse_Entity_Commission", commissionJson)
[Rest of my form]
呈现为:
<input id="DataResponse_Entity_Commission" name="DataResponse_Entity_Commission" type="hidden" value="["RangeStart":0,"RangeEnd":0,"CommissionPercent":2.00000,"RangeStart":1,"RangeEnd":2,"CommissionPercent":3.00000,"RangeStart":2,"RangeEnd":0,"CommissionPercent":2.00000,"RangeStart":3,"RangeEnd":2,"CommissionPercent":1.00000,"RangeStart":15,"RangeEnd":10,"CommissionPercent":5.00000]">
在我的情况下,我在回发之前做了一些 JS 的东西来编辑隐藏字段中的 json
然后我在我的控制器中再次使用 Newtonsoft 进行反序列化:
string jsonCommissionRange = Request.Form["DataResponse_Entity_Commission"];
List<CommissionRange> commissionRange = JsonConvert.DeserializeObject<List<CommissionRange>>(jsonCommissionRange);
【讨论】:
这对我有用。我认为接受的解决方案要干净得多。【参考方案5】:Html.HiddenFor
仅用于一个值。在创建隐藏字段之前,您需要以某种方式序列化您的列表。
例如,如果您的列表是字符串类型,您可以将列表加入一个逗号分隔的列表,然后在您的控制器中回发后拆分该列表。
【讨论】:
【参考方案6】:我刚刚发现(经过几个小时试图弄清楚为什么模型值没有返回到控制器)隐藏的应该遵循 EditorFor。
除非我做错了什么,否则这就是我发现的。我不会再犯错了。
在包含另一个类列表的模型的上下文中。
这不起作用:
@
for (int i = 0; i < Model.Categories.Count; i++)
<tr>
<td>
@Html.HiddenFor(modelItem => Model.Categories[i].Id)
@Html.HiddenFor(modelItem => Model.Categories[i].ProductCategoryId)
@Html.HiddenFor(modelItem => Model.Categories[i].CategoryName)
@Html.DisplayFor(modelItem => Model.Categories[i].CategoryName)
</td>
<td>
@Html.HiddenFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
@Html.EditorFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
@Html.ValidationMessageFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
</td>
<td style="text-align: center">
@Html.HiddenFor(modelItem => Model.Categories[i].IsSelected)
@Html.EditorFor(modelItem => Model.Categories[i].IsSelected)
</td>
</tr>
这将在哪里......
for (int i = 0; i < Model.Categories.Count; i++)
<tr>
<td>
@Html.HiddenFor(modelItem => Model.Categories[i].Id)
@Html.HiddenFor(modelItem => Model.Categories[i].ProductCategoryId)
@Html.HiddenFor(modelItem => Model.Categories[i].CategoryName)
@Html.DisplayFor(modelItem => Model.Categories[i].CategoryName)
</td>
<td>
@Html.EditorFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
@Html.HiddenFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
@Html.ValidationMessageFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
</td>
<td style="text-align: center">
@Html.EditorFor(modelItem => Model.Categories[i].IsSelected)
@Html.HiddenFor(modelItem => Model.Categories[i].IsSelected)
</td>
</tr>
【讨论】:
【参考方案7】:我开始挖掘HiddenFor
的源代码,我认为您看到的障碍是您的复杂对象MyList
不能隐式转换为类型string
,因此框架会处理您的Model
值为null
并将value
属性呈现为空。
【讨论】:
【参考方案8】:你可以看看这个solution。
仅将 HiddenFor 放在 EditorTemplate 中。
在您的视图中输入:@Html.EditorFor(model => model.MyList)
它应该可以工作。
【讨论】:
【参考方案9】:面临同样的问题。没有 for 循环,它只发布列表的第一个元素。遍历for循环后,可以保持完整列表并成功发布。
@if (Model.MyList!= null)
for (int i = 0; i < Model.MyList.Count; i++)
@Html.HiddenFor(x => x.MyList[i])
【讨论】:
【参考方案10】:另一种选择是:
<input type="hidden" value=@(string.Join(",", Model.MyList)) />
【讨论】:
这也是我的第一个想法。但是我有一个视图模型,它期望 MyList 字段的 int[] 和逗号分隔的字符串不会被 MVC 绑定机制解析为数组。【参考方案11】:foreach
循环而不是 for
循环可能是一个更清洁的解决方案。
@foreach(var item in Model.ToGroups)
@Html.HiddenFor(model => item)
【讨论】:
【参考方案12】:解决此问题的另一种可能方法是为 List 中的每个对象指定一个 ID,然后使用 @Html.DropDownListFor(model => model.IDs)
并填充一个包含 ID 的数组。
【讨论】:
【参考方案13】:也许晚了,但我为集合中的隐藏字段创建了扩展方法(使用简单的数据类型项):
原来是这样:
/// <summary>
/// Returns an HTML hidden input element for each item in the object's property (collection) that is represented by the specified expression.
/// </summary>
public static IHtmlString HiddenForCollection<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression) where TProperty : ICollection
var model = html.ViewData.Model;
var property = model != null
? expression.Compile().Invoke(model)
: default(TProperty);
var result = new StringBuilder();
if (property != null && property.Count > 0)
for(int i = 0; i < property.Count; i++)
var modelExp = expression.Parameters.First();
var propertyExp = expression.Body;
var itemExp = Expression.ArrayIndex(propertyExp, Expression.Constant(i));
var itemExpression = Expression.Lambda<Func<TModel, object>>(itemExp, modelExp);
result.AppendLine(html.HiddenFor(itemExpression).ToString());
return new MvcHtmlString(result.ToString());
用法很简单:
@Html.HiddenForCollection(m => m.MyList)
【讨论】:
以上是关于@Html.HiddenFor 不适用于 ASP.NET MVC 中的列表的主要内容,如果未能解决你的问题,请参考以下文章
Html.Hidden 和 Html.HiddenFor 有啥区别