@ Html.HiddenFor не работает со списками в ASP.NET MVC - PullRequest
82 голосов
/ 22 февраля 2012

Я использую модель, которая содержит список в качестве свойства. Я заполняю этот список элементами, которые я беру с SQL Server. Я хочу, чтобы список был скрыт в представлении и передан действию POST. Позже я могу захотеть добавить больше элементов в этот список с помощью jQuery, что делает массив непригодным для расширения в дальнейшем. Обычно вы используете

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

для выполнения этой функции, но по какой-то причине список в POST всегда равен нулю.

Очень простой вопрос, кто-нибудь знает, почему MVC ведет себя так?

Ответы [ 12 ]

132 голосов
/ 29 сентября 2014

Я только что столкнулся с этой проблемой и решил ее, просто выполнив следующее:

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

При использовании for вместо foreach привязка модели будет работать правильно и подберет все скрытые значения в списке. Похоже, самый простой способ решить эту проблему.

28 голосов
/ 22 февраля 2012

HiddenFor не похож на DisplayFor или EditorFor. Он не будет работать с коллекциями, только отдельные значения.

Вы можете использовать помощник по сериализации HTML, доступный в проекте MVC Futures, для сериализации объекта в скрытое поле, или вам придется написать код самостоятельно. Лучшее решение - просто сериализовать какой-либо идентификатор и повторно получить данные из базы данных при обратной передаче.

13 голосов
/ 15 января 2014

Это что-то вроде хака, но если @Html.EditorFor или @Html.DisplayFor работают для вашего списка, если вы хотите убедиться, что оно отправлено в запросе на публикацию, но не отображается, вы можете просто применить его к display: none; чтобы скрыть это, например:

<div style="display: none;">@Html.EditorFor(model => model.MyList)</div>
8 голосов
/ 26 ноября 2015

Как насчет использования 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);
6 голосов
/ 22 февраля 2012

Html.HiddenFor рассчитан только на одно значение.Вам нужно каким-то образом сериализовать свой список перед созданием скрытого поля.

Например, если ваш список имеет тип string, вы можете объединить список в список через запятую, а затем разбить список после записи.обратно в свой контроллер.

4 голосов
/ 09 октября 2015

Я только что выяснил (после нескольких часов попыток выяснить, почему значения модели не возвращаются в контроллер), что скрытое значение должно следовать за 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>
            }
3 голосов
/ 23 ноября 2017

Столкнулся с той же проблемой. Без цикла for он разместил только первый элемент списка. После выполнения цикла for он может сохранить полный список и успешно опубликовать сообщение.

 @if (Model.MyList!= null)
    {
    for (int i = 0; i < Model.MyList.Count; i++)
      {
        @Html.HiddenFor(x => x.MyList[i])
      }
    }
3 голосов
/ 15 ноября 2012

Вы можете взглянуть на это решение .

Поместите только скрытое для внутри EditorTemplate.

И в вашем представлении укажите это: @Html.EditorFor(model => model.MyList)

Должно работать.

3 голосов
/ 22 февраля 2012

Я начал копаться в исходном коде HiddenFor, и я думаю, что препятствие, которое вы видите, заключается в том, что ваш сложный объект MyList неявно не преобразуется в тип string, поэтому инфраструктура обрабатывает ваш Model значение равно null и атрибут value остается пустым.

2 голосов
/ 16 марта 2018

Другой вариант будет:

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