[英]@Html.HiddenFor does not work on Lists in ASP.NET MVC
我正在使用一個包含 List 作為屬性的模型。 我正在使用從 SQL Server 獲取的項目填充此列表。 我希望列表隱藏在視圖中並傳遞給 POST 操作。 稍后我可能想用 jQuery 向這個 List 添加更多項目,這使得數組不適合以后擴展。 通常你會使用
@Html.HiddenFor(model => model.MyList)
完成此功能,但由於某種原因,POST 中的列表始終為空。
非常簡單的問題,有人知道為什么 MVC 會這樣嗎?
我剛剛遇到這個問題並通過執行以下操作解決了它:
@for(int i = 0; i < Model.ToGroups.Count; i++)
{
@Html.HiddenFor(model => Model.ToGroups[i])
}
通過使用for
而不是foreach
模型綁定將正常工作並拾取列表中的所有隱藏值。 似乎是解決此問題的最簡單方法。
HiddenFor 不像 DisplayFor 或 EditorFor。 它不適用於集合,僅適用於單個值。
您可以使用 MVC Futures 項目中提供的 Serialize HTML 幫助器將對象序列化為隱藏字段,或者您必須自己編寫代碼。 更好的解決方案是簡單地序列化某種 ID 並在回發時從數據庫中重新獲取數據。
這有點 hack,但是如果@Html.EditorFor
或@Html.DisplayFor
為您的列表工作,如果您想確保它在發布請求中發送但不可見,您可以將其設置為使用display: none;
改為隱藏它,例如:
<div style="display: none;">@Html.EditorFor(model => model.MyList)</div>
如何使用 Newtonsoft 將對象反序列化為 json 字符串,然后將其插入到您的隱藏字段中,例如( Model.DataResponse.Entity.Commission是一個簡單的“CommissionRange”對象列表,您將在 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);
Html.HiddenFor
只為一個值而設計。 在創建隱藏字段之前,您需要以某種方式序列化您的列表。
例如,如果您的列表是字符串類型,您可以將列表加入逗號分隔列表,然后在回發到控制器后拆分列表。
我剛剛發現(經過幾個小時試圖弄清楚為什么模型值沒有返回到控制器)隱藏的應該遵循 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>
}
你可以看看這個解決方案。
僅將 HiddenFor 放在 EditorTemplate 中。
在你的視圖中放這個: @Html.EditorFor(model => model.MyList)
它應該有效。
面臨同樣的問題。 如果沒有 for 循環,它只會發布列表的第一個元素。 遍歷for循環后,可以保持完整列表並成功發布。
@if (Model.MyList!= null)
{
for (int i = 0; i < Model.MyList.Count; i++)
{
@Html.HiddenFor(x => x.MyList[i])
}
}
我開始研究HiddenFor
的源代碼,我認為您看到的障礙是您的復雜對象MyList
不能隱式轉換為類型string
,因此框架將您的Model
值視為null
並將value
屬性呈現為空。
另一種選擇是:
<input type="hidden" value=@(string.Join(",", Model.MyList)) />
foreach
循環而不是for
循環可能是一個稍微干凈的解決方案。
@foreach(var item in Model.ToGroups)
{
@Html.HiddenFor(model => item)
}
解決此問題的另一種可能方法是給 List 中的每個對象一個 ID,然后使用@Html.DropDownListFor(model => model.IDs)
並填充一個包含 ID 的數組。
也許遲了,但我為集合中的隱藏字段創建了擴展方法(使用簡單的數據類型項):
所以這里是:
/// <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)
除了這個答案,我還有一個具有各種屬性的模型,其中一些是 IEnumerables。 我所做的是將它序列化到視圖中的一個變量中:
@{
var serializedObject = JsonSerializer.Serialize(Model);
}
然后,將該字符串放入 Hidden 元素中(因為 HiddenFor 旨在用於模型中的單個值),如下所示:
@Html.Hidden("serialized", @serializedObject)
最后,在控制器中,我可以反序列化它
JsonSerializer.Deserialize<MyType>(Request.Form["serialized"])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.