@ Html.HiddenFor不适用于ASP.NET MVC中的列表

时间:2012-02-21 21:15:26

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

我正在使用包含List作为属性的模型。我正在使用从SQL Server中获取的项目填充此列表。我希望List隐藏在视图中并传递给POST操作。稍后我可能想要使用jQuery向此List添加更多项目,这使得数组不适合稍后进行扩展。通常你会使用

@Html.HiddenFor(model => model.MyList)

完成此功能,但由于某种原因,POST中的List始终为null。

非常简单的问题,任何人都知道为什么MVC会像这样?

13 个答案:

答案 0 :(得分:129)

我刚刚遇到这个问题并通过以下方式解决了这个问题:

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

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

答案 1 :(得分:28)

HiddenFor不像DisplayFor或EditorFor。它不适用于集合,只适用于单个值。

您可以使用MVC Futures项目中提供的Serialize HTML帮助程序将对象序列化为Hidden字段,或者您必须自己编写代码。更好的解决方案是简单地序列化某种ID,并在回发时从数据库中重新获取数据。

答案 2 :(得分:13)

这有点像黑客,但如果@Html.EditorFor@Html.DisplayFor适用于您的列表,如果您想确保它在帖子请求中发送但不可见,您可以将其设置为使用display: none;代替隐藏它,例如:

<div style="display: none;">@Html.EditorFor(model => model.MyList)</div>

答案 3 :(得分:8)

如何使用Newtonsoft将对象反序列化为json字符串,然后将其插入到Hidden字段中,例如 ( Model.DataResponse.Entity.Commission 是简单&#34; CommissionRange&#34; 对象的列表,因为您会看到在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);

答案 4 :(得分:6)

Html.HiddenFor仅适用于一个值。在创建隐藏字段之前,您需要以某种方式序列化列表。

例如,如果您的列表是字符串类型,则可以将列表加入逗号分隔列表,然后在控制器中回发后拆分列表。

答案 5 :(得分:4)

我刚刚发现(经过几个小时试图弄清楚为什么模型值不会返回控制器)隐藏的应该遵循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>
            }

答案 6 :(得分:3)

我开始深入挖掘HiddenFor的源代码,我认为您遇到的障碍是您的复杂对象MyList无法隐式转换为string类型,因此框架将您的Model值视为null,并将value属性设为空。

答案 7 :(得分:3)

您可以查看此solution

在EditorTemplate中只放置HiddenFor。

在你的视图中输入:@Html.EditorFor(model => model.MyList)

它应该有用。

答案 8 :(得分:3)

面临同样的问题。没有for循环,它只发布了列表的第一个元素。迭代完循环后,它可以保持完整列表并成功发布。

 @if (Model.MyList!= null)
    {
    for (int i = 0; i < Model.MyList.Count; i++)
      {
        @Html.HiddenFor(x => x.MyList[i])
      }
    }

答案 9 :(得分:2)

另一种选择是:

<input type="hidden" value=@(string.Join(",", Model.MyList)) />

答案 10 :(得分:1)

解决此问题的另一种可能方法是为List中的每个对象提供一个ID,然后使用@Html.DropDownListFor(model => model.IDs)并填充一个包含ID的数组。

答案 11 :(得分:1)

可能很晚,但是我为集合中的隐藏字段创建了扩展方法(使用简单的数据类型项):

所以这是:

 <div class="col text-right">
<div ngbDropdown placement="top-right" class="d-inline-block">
  <button class="btn btn-outline-primary" id="dropdownBasic2" ngbDropdownToggle>Toggle dropup</button>
  <div ngbDropdownMenu aria-labelledby="dropdownBasic2">
    <button class="dropdown-item">Action - 1</button>
    <button class="dropdown-item">Another Action</button>
    <button class="dropdown-item">Something else is here</button>
  </div>
</div>

用法很简单:

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

答案 12 :(得分:0)

class ApplicationController < ActionController::Base protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' } end 循环而不是foreach循环可能是一种更简洁的解决方案。

for