【问题标题】:@Html.HiddenFor does not work on Lists in ASP.NET MVC@Html.HiddenFor 不适用于 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 是什么类型?您可能需要手动对列表执行一些序列化/反序列化。

标签: c# asp.net asp.net-mvc-3 hidden-field


【解决方案1】:

我刚刚遇到这个问题,只需执行以下操作即可解决:

@for(int i = 0; i < Model.ToGroups.Count; i++)
{
    @Html.HiddenFor(model => Model.ToGroups[i])
}

通过使用for 而不是foreach,模型绑定将正常工作并拾取列表中的所有隐藏值。似乎是解决此问题的最简单方法。

【讨论】:

  • 谢谢!拯救了我的夜晚。
  • 谢谢 - 不错的简单解决方案。不过只需要一个小模块:需要引用对象的 Id 字段。所以如果该字段被称为 RowId,那么:@Html.HiddenFor(model =&gt; Model.ToGroups[i].RowId)
  • 为我工作,即使我在集合中的模型上有多个字段时也是如此。 IE。 @Html.EditorFor(model =&gt; Model.ToGroups[i].Id) 下一次是 @Html.EditorFor(model =&gt; Model.ToGroups[i].Description) - 都在 for 循环中。控制器能够将其映射到具有这些字段的模型列表。为了确保它没有出现在屏幕上,只需将其包围在&lt;div style="display: none;"&gt;&lt;/div&gt;
  • @user3186023 在这里回答一个非常老的评论,但也许其他人会遇到同样的问题:将for-loop 更改为:for(int i = 0; i &lt; 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 =&gt; 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 =&gt; 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)
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-06-10
                  • 2011-01-08
                  • 1970-01-01
                  • 2020-05-14
                  • 2015-08-15
                  • 1970-01-01
                  • 2019-10-31
                  • 2014-10-19
                  相关资源
                  最近更新 更多