簡體   English   中英

@Html.HiddenFor 不適用於 ASP.NET MVC 中的列表

[英]@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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM