@Html.HiddenFor не работает в списках в ASP.NET MVC
Я использую модель, содержащую Список как свойство. Я заполняю этот список элементами, которые я извлекаю из SQL Server. Я хочу, чтобы список был скрыт в представлении и передан в действие POST. Позже я могу добавить еще несколько элементов в этот список с помощью jQuery, который впоследствии сделает массив неподходящим для расширения. Обычно вы используете
@Html.HiddenFor(model => model.MyList)
для выполнения этой функции, но по какой-либо причине список в POST всегда равен нулю.
Очень простой вопрос, кто-нибудь знает, почему MVC ведет себя так?
Ответы
Ответ 1
Я только что столкнулся с этой проблемой и решил ее, просто выполнив следующее:
@for(int i = 0; i < Model.ToGroups.Length; i++)
{
@Html.HiddenFor(model => Model.ToGroups[i])
}
При использовании for вместо foreach привязка модели будет работать правильно и заберет все скрытые значения в списке. Похоже, самый простой способ решить эту проблему.
Ответ 2
HiddenFor не похож на DisplayFor или EditorFor. Он не будет работать с коллекциями, только с одиночными значениями.
Вы можете использовать вспомогательный помощник Serialize HTML, доступный в проекте MVC Futures, для сериализации объекта в поле Скрытый, или вам придется писать код самостоятельно. Лучшее решение - просто сериализовать идентификатор некоторого типа и повторно получить данные из базы данных после обратной передачи.
Ответ 3
Это немного взломать, но если @Html.EditorFor
или @Html.DisplayFor
работают для вашего списка, если вы хотите, чтобы он был отправлен на почтовый запрос, но не был видимым, вы могли бы просто создать его с помощью display: none;
чтобы скрыть его, например:
<div style="display: none;">@Html.EditorFor(model => model.MyList)</div>
Ответ 4
Как насчет использования 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);
Ответ 5
Html.HiddenFor
предназначен только для одного значения. Вам нужно будет сериализовать свой список каким-то образом, прежде чем создавать скрытое поле.
Например, если ваш список имеет строку типа, вы можете присоединиться к списку в список, разделенный запятыми, а затем разбить список после отправки обратно в ваш контроллер.
Ответ 6
Я только что узнал (через пару часов, пытаясь понять, почему значения модели не возвращаются к контроллеру), которые скрыты, должны следовать за редактором.
Если я не делаю что-то другое, это то, что я нашел. Я больше не буду ошибаться.
В контексте модели, содержащей список другого класса.
Это НЕ будет работать:
@{
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
Вы можете взглянуть на это решение.
Поместите только HiddenFor внутри EditorTemplate.
И в вашем представлении поставьте это: @Html.EditorFor(model => model.MyList)
Он должен работать.
Ответ 9
Столкнулась с той же проблемой. Без цикла он только разместил первый элемент списка. После повторения цикла for он может содержать полный список и успешно опубликовать.
@if (Model.MyList!= null)
{
for (int i = 0; i < Model.MyList.Count; i++)
{
@Html.HiddenFor(x => x.MyList[i])
}
}
Ответ 10
Другой вариант будет:
<input type="hidden" [email protected](string.Join(",", Model.MyList)) />
Ответ 11
Еще один возможный способ исправить это - предоставить каждому объекту в вашем списке идентификатор, затем использовать @Html.DropDownListFor(model => model.IDs)
и заполнить массив, содержащий идентификаторы.
Ответ 12
может быть поздно, но я создал метод расширения для скрытых полей из коллекции (с простыми элементами типа данных):
Итак, вот оно:
/// <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());
}
Использование так же просто, как:
@Html.HiddenForCollection(m => m.MyList)