@ Html.HiddenFor does not work on lists in ASP.NET MVC

I am using a model containing a List as a property. I populate this list with elements that I retrieve from SQL Server. I want the list to be hidden in the view and passed to the POST action. Later, I can add a few more elements to this list with jQuery, which subsequently makes the array unsuitable for expansion. Usually you use

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

to execute this function, but for some reason, the list in POST is always zero.

A very simple question, does anyone know why MVC behaves this way?

+80
c # asp.net-mvc-3 hidden-field
Feb 21 '12 at 21:15
source share
12 answers

I just ran into this problem and solved it simply by doing the following:

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

When using for instead of foreach, model binding will work correctly and will pick up all hidden values ​​in the list. It seems like the easiest way to solve this problem.

+128
Sep 29 '14 at 6:13
source share

HiddenFor is not like DisplayFor or EditorFor. It will not work with collections, only with single values.

You can use the Serialize HTML helper helper available in the MVC Futures project to serialize the object in the Hidden field, or you will have to write the code yourself. The best solution is to simply serialize an identifier of some type and retrieve the data from the database after the postback.

+28
Feb 21 2018-12-21T00:
source share

This is a bit of a hack, but if @Html.EditorFor or @Html.DisplayFor work for your list, if you want it to be sent to an email request but not visible, you could just create it using display: none; to hide it, for example:

 <div style="display: none;">@Html.EditorFor(model => model.MyList)</div> 
+13
Jan 15 '14 at 15:32
source share

How about using Newtonsoft to deserialize an object into a json string, and then paste it into the hide field, for example. ( Model.DataResponse.Entity.Commission is a list of simple "CommissionRange" objects, as you will see in 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] } 

Refers to:

 <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}]"> 

In my case, I am doing some JS stuff to edit json in a hidden field before sending back

In my controller, I again use Newtonsoft to deserialize:

 string jsonCommissionRange = Request.Form["DataResponse_Entity_Commission"]; List<CommissionRange> commissionRange = JsonConvert.DeserializeObject<List<CommissionRange>>(jsonCommissionRange); 
+8
Nov 25 '15 at 22:37
source share

Html.HiddenFor is for one value only. You will need to serialize your list in some way before creating a hidden field.

For example, if your list has a string like, you can join the list in a comma separated list, and then split the list after sending it back to your controller.

+6
Feb 21 2018-12-21T00:
source share

I just found out (after a couple of hours, trying to understand why the model values ​​do not return to the controller), which are hidden, should follow the editor.

If I do not do something else, this is what I found. I will no longer be mistaken.

In the context of a model containing a list of another class.

This will NOT work:

  @{ 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> } } 

Where will it be ...

  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> } 
+4
09 Oct '15 at 12:43 on
source share

I started digging the source code for HiddenFor , and I think the road block you see is that your complex MyList object is implicitly converted to type string , so the structure considers your Model to be null and discards the value attribute.

+3
Feb 21 '12 at 21:52
source share

You can take a look at this solution .

Place only HiddenFor inside the EditorTemplate.

And in your view put this: @Html.EditorFor(model => model.MyList)

It should work.

+3
Nov 15 '12 at 8:40
source share

Faced the same problem. Without a loop, he only placed the first element of the list. After repeating the for loop, it may contain a complete list and publish successfully.

  @if (Model.MyList!= null) { for (int i = 0; i < Model.MyList.Count; i++) { @Html.HiddenFor(x => x.MyList[i]) } } 
+3
Nov 23 '17 at 8:55
source share

Another option would be:

 <input type="hidden" value=@(string.Join(",", Model.MyList)) /> 
+2
Mar 16 '18 at 19:30
source share

Another possible way to fix this is to provide each object in your list with an identifier, then use @Html.DropDownListFor(model => model.IDs) and populate the array containing the identifiers.

+1
Jun 24 '14 at 20:43
source share

It may be late, but I created an extension method for hidden fields from the collection (with simple data type elements):

So here it is:

 /// <summary> /// Returns an HTML hidden input element for each item in the object 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()); } 

Use is as simple as:

 @Html.HiddenForCollection(m => m.MyList) 
+1
Sep 20 '17 at 9:30
source share



All Articles