@ Html.HiddenFor는 ASP.NET MVC의 목록에서 작동하지 않습니다.


97

List를 속성으로 포함하는 모델을 사용하고 있습니다. 이 목록을 SQL Server에서 가져온 항목으로 채우고 있습니다. 목록이 뷰에서 숨겨지고 POST 작업에 전달되기를 원합니다. 나중에 jQuery를 사용하여이 목록에 더 많은 항목을 추가하여 나중에 확장에 적합하지 않은 배열을 만들고 싶을 수 있습니다. 일반적으로 당신은

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

이 기능을 수행하기 위해 어떤 이유로 POST의 목록은 항상 null입니다.

매우 간단한 질문입니다. MVC가 왜 이렇게 작동하는지 아는 사람이 있습니까?


1
일반적으로 전체 목록을 그렇게 숨기지는 않습니다. <input />s 측면에서 원하는 출력은 무엇입니까 ?
Cᴏʀʏ 2012

1
무엇이 MyList포함되어 있습니까? HiddenFor한 번에 하나의 입력에만 사용됩니다.
Daniel A. White

1
어떤 유형 Model.MyList입니까? 목록에서 수동으로 직렬화 / 역 직렬화를 수행해야 할 수도 있습니다.
Kyle Trauberman 2012


답변:


161

나는 방금이 문제를 발견하고 다음을 수행하여 간단히 해결했습니다.

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

foreach 대신 for를 사용하면 모델 바인딩이 올바르게 작동하고 목록에서 숨겨진 값을 모두 선택합니다. 이 문제를 해결하는 가장 간단한 방법 인 것 같습니다.


5
감사! 내 밤을 구했습니다.
TSmith 2015 년

7
감사합니다-멋진 간단한 솔루션입니다. 하지만 작은 모드 만 필요합니다. 객체의 Id 필드를 참조해야합니다. 따라서 필드 이름이 RowId이면 다음과 같습니다.@Html.HiddenFor(model => Model.ToGroups[i].RowId)
Krishna Gupta 2015

3
컬렉션의 모델에 대한 여러 분야가 있었을 때도 나를 위해 일했습니다. 즉 @Html.EditorFor(model => Model.ToGroups[i].Id)다음 @Html.EditorFor(model => Model.ToGroups[i].Description)에 대한 루프에서 모두 - 다음 번에. 그리고 컨트롤러는 해당 필드가있는 모델 목록에이를 매핑 할 수있었습니다. 그리고 확신 것도 화면에 보여주지하기 위해, 그냥 그것을 둘러싸고<div style="display: none;"></div>
돈 치들

훌륭한! 잘하셨습니다. 나를 위해 일했습니다!
AxleWack

3
@ user3186023 여기에 정말 오래된 댓글에 답하는 중이지만 다른 사람이 같은 문제를 for겪을 수도 있습니다. -loop를 다음과 같이 변경합니다 .for(int i = 0; i < Model.Departments.Count(); i++)
Stian

28

HiddenFor는 DisplayFor 또는 EditorFor와 다릅니다. 컬렉션에서는 작동하지 않으며 단일 값만 사용할 수 있습니다.

MVC Futures 프로젝트에서 사용할 수있는 Serialize HTML 도우미를 사용하여 개체를 Hidden 필드에 직렬화하거나 코드를 직접 작성해야합니다. 더 나은 솔루션은 단순히 일종의 ID를 직렬화하고 포스트 백시 데이터베이스에서 데이터를 다시 가져 오는 것입니다.


예가 있습니까? 나는 이것을 시도했지만 양식이 제출되었을 때 ViewModel 값에 바인딩하지 못했습니다.
Alan Macdonald 2013 년

@AlanMacdonald-바인딩에 실패하면 이름이 올바르지 않기 때문이며 인덱서가있는 for 대신 foreach를 사용했기 때문일 가능성이 큽니다. 또는 바인딩에서 적절한 속성을 사용하지 않았을 수 있습니다. weblogs.asp.net/shijuvarghese/archive/2010/03/06/…
Erik Funkenbusch 2013 년

감사. 실제로 내가 시도했을 때 그것은 말 그대로 @ Html.Serialize ( "Model.ModelIDs", Model.ModelIDs) 였는데 Model은 내 ViewModel이고 ModelIDs int 배열 속성이 있습니다. 그래서 루프 나 아무것도 없었습니다. 양식이 제출되었을 때 ModelID는 바인딩 된 ViewModel에서 항상 null이었습니다.
Alan Macdonald 2013 년

@AlanMacdonald-이름에 "모델"을 포함하지 않습니다.
Erik Funkenbusch 2013 년

16

그것은 약간의 해킹이지만 목록에 대해 작동 @Html.EditorFor하거나 @Html.DisplayFor게시 요청에 전송되었는지 확인하고 싶지만 표시되지 않도록하려면 스타일을 지정하여 display: none;대신 숨길 수 있습니다. 예 :

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

요청 후 모델에 값이 저장되지는 ​​않습니다.
nldev

.EditorFor가 올바르게 작동하도록 설정되어 있다면 이것도 작동 할 것입니다.
Mark Rhodes

9

Newtonsoft를 사용하여 객체를 json 문자열로 역 직렬화 한 다음 숨겨진 필드에 삽입하는 것은 어떻습니까? 예를 들어 ( Model.DataResponse.Entity.Commission 은 JSON에서 볼 수있는 간단한 "CommissionRange" 객체 목록 입니다 )

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

제 경우에는 다시 게시하기 전에 숨겨진 필드에서 json을 편집하기 위해 JS 작업을 수행합니다.

내 컨트롤러에서 Newtonsoft를 다시 사용하여 역 직렬화합니다.

string jsonCommissionRange = Request.Form["DataResponse_Entity_Commission"];
List<CommissionRange> commissionRange = JsonConvert.DeserializeObject<List<CommissionRange>>(jsonCommissionRange);

이것은 나를 위해 일했습니다. 나는 받아 들여진 해결책이 훨씬 더 깨끗하다고 ​​생각했다.
e-on

6

Html.HiddenFor하나의 값만을 위해 설계되었습니다. 숨겨진 필드를 만들기 전에 어떤 방식 으로든 목록을 직렬화해야합니다.

예를 들어 목록이 문자열 유형 인 경우 목록을 쉼표로 구분 된 목록으로 결합한 다음 컨트롤러에 다시 게시 한 후 목록을 분할 할 수 있습니다.


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

3

에 대한 소스 코드를 파헤 치기 시작했고 HiddenFor, 여러분이보고있는 장애물은 복잡한 객체 MyList가 암시 적으로 type으로 변환 할 수 없다는 string것이므로 프레임 워크가 Model값을 처리 null하고 value속성을 비워 둡니다.


3

솔루션을 살펴볼 수 있습니다. .

EditorTemplate 안에 HiddenFor 만 넣으십시오.

그리고 당신의 뷰에 이것을 넣으십시오. @Html.EditorFor(model => model.MyList)

작동합니다.


3

같은 문제에 직면했습니다. for 루프가 없으면 목록의 첫 번째 요소 만 게시되었습니다. for 루프를 반복 한 후 전체 목록을 유지하고 성공적으로 게시 할 수 있습니다.

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

2

또 다른 옵션은 다음과 같습니다.

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

이것은 나의 첫 번째 아이디어이기도했습니다. 그러나 MyList 필드에 대해 int []를 예상하고 쉼표로 구분 된 문자열이 MVC 바인딩 메커니즘에 의해 배열로 구문 분석되지 않는 뷰 모델이 있습니다.
Tadej Mali

2

foreach대신 루프 for루프는 약간 청소기의 솔루션이 될 수 있습니다.

@foreach(var item in Model.ToGroups)
{
    @Html.HiddenFor(model => item)
}

1

이 문제를 해결할 수있는 또 다른 방법은 목록의 각 개체에 ID @Html.DropDownListFor(model => model.IDs)를 부여한 다음 ID를 보유하는 배열 을 사용 하고 채우는 것입니다.


1

늦었을 수도 있지만 컬렉션에서 숨겨진 필드에 대한 확장 메서드를 만들었습니다 (간단한 데이터 유형 항목 포함).

그래서 여기 있습니다 :

/// <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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.