CheckBoxFor가 추가 입력 태그를 렌더링하는 이유는 무엇이며 FormCollection을 사용하여 값을 얻는 방법은 무엇입니까?


130

내 ASP.NET MVC 앱에서 다음 코드를 사용하여 확인란을 렌더링합니다.

<%= Html.CheckBoxFor(i=>i.ReceiveRSVPNotifications) %>

이제 이것이 확인란 입력 태그와 숨겨진 입력 태그를 모두 렌더링한다는 것을 알았습니다 . 내가 겪고있는 문제는 FormCollection을 사용하여 확인란에서 값을 검색하려고 할 때입니다.

FormValues["ReceiveRSVPNotifications"]

"true, false"값을 얻습니다. 렌더링 된 HTML을 보면 다음을 볼 수 있습니다.

 <input id="ReceiveRSVPNotifications" name="ReceiveRSVPNotifications" value="true" type="checkbox">
 <input name="ReceiveRSVPNotifications" value="false" type="hidden">

따라서 FormValues ​​컬렉션은 이름이 같기 때문에이 두 값을 결합하는 것으로 보입니다.

어떤 아이디어?

답변:


168

여기를보세요 :

http://forums.asp.net/t/1314753.aspx

이것은 버그가 아니며 실제로 Ruby on Rails와 MonoRail이 사용하는 것과 동일한 접근 방식입니다.

확인란이있는 양식을 제출하면 확인란이 선택된 경우에만 값이 게시됩니다. 따라서 확인란을 선택하지 않으면 많은 상황에서 false를 보내려고 할 때 서버로 아무것도 보내지 않습니다. 숨겨진 입력은 확인란과 이름이 같으므로 확인란이 선택되어 있지 않으면 여전히 서버에 'false'가 전송됩니다.

확인란을 선택하면 ModelBinder가 자동으로 'true, false'에서 'true'를 추출합니다.


10
좋은 설명이지만 경우에 따라 ckecbox를 선택하지 않은 경우 쿼리 문자열에 '아무것도 얻지 않을 수 있습니다. 따라서 기본 동작입니다. HTML 도우미를 사용하여 가능합니까, 아니면 단순히 <input>태그 를 사용해야합니까?
Maksymilian Majer 2016 년

13
내가 사용이 얻을 검색 페이지가 지금 내 URL이 ... 참 / 거짓 PARAMS 가득합니다 .... 이런 식으로 해달라고
숀 맥클린

1
와우, 그것은 예기치 않은 일이다. 이것은 HTML 체크 박스가 실제로 "깨진"것을 의미합니까?
Isantipov

1
@Isantipov : 아니요, 단지이 웹 프레임 워크가 확인란을 표시하기 위해 게시 된 값 이 없는 것에 의존하지 않음 을 의미 false합니다. 아래의 RyanJMcGowan의 답변을보십시오. "숨겨진 입력을 보내면 요청이 제출 될 때 해당 확인란이 페이지에 있음을 알 수 있습니다."
Robert Harvey

1
글쎄, 로버트, 이것은 나를 위해 작동하지 않습니다. 내 chbox MyCheckbox 가 선택되어 있지 않으면 false가 표시되고 MyCheckbox 가 선택 되면 값으로 [true, false] 배열이 표시됩니다. 나는 전체 양식을 직렬화하고 그것을 아약스를 통해 컨트롤러 작업에 전달합니다. AddToOrder (MyModel model) 여기서 model.MyCheckbox = true 대신에 false를
얻음

18

나는 Shawn (위)과 같은 문제가있었습니다. 이 접근 방식은 POST에는 좋을 수 있지만 실제로 GET에는 짜증이납니다. 따라서 숨겨진 필드를 뛰어 넘는 간단한 Html 확장을 구현했습니다.

public static MvcHtmlString BasicCheckBoxFor<T>(this HtmlHelper<T> html, 
                                                Expression<Func<T, bool>> expression,
                                                object htmlAttributes = null)
{
    var result = html.CheckBoxFor(expression).ToString();
    const string pattern = @"<input name=""[^""]+"" type=""hidden"" value=""false"" />";
    var single = Regex.Replace(result, pattern, "");
    return MvcHtmlString.Create(single);
}

내가 지금 가지고있는 문제는 코드를 깨기 위해 MVC 프레임 워크를 변경하고 싶지 않다는 것입니다. 따라서이 새로운 계약을 설명하는 테스트 범위가 있는지 확인해야합니다.


5
체크 박스 입력 만 작성 하는 대신 정규식을 사용하여 숨겨진 입력을 일치 / 제거하는 것이 더럽지 않습니까? :)
Tim Hobbs

2
아니요, 저는 제 자신을 재 구현하지 않고 기존의 행동을 수정하고있었습니다. 그렇게하면 내 변경이 MS가 출시 한 모든 변경에 보조를 맞출 수 있습니다.
Chris Kemp

10
작은 관찰입니다. 구현시 전달 된 사용자 정의 속성이 렌더링되지 않습니다. "htmlAttributes"매개 변수는 원래 "CheckBoxFor"메소드로 전달되지 않습니다.
Emil Lundin

16

이 대체 방법을 사용하여 GET 양식의 확인란을 렌더링합니다.

/// <summary>
/// Renders checkbox as one input (normal Html.CheckBoxFor renders two inputs: checkbox and hidden)
/// </summary>
public static MvcHtmlString BasicCheckBoxFor<T>(this HtmlHelper<T> html, Expression<Func<T, bool>> expression, object htmlAttributes = null)
{
    var tag = new TagBuilder("input");

    tag.Attributes["type"] = "checkbox";
    tag.Attributes["id"] = html.IdFor(expression).ToString();
    tag.Attributes["name"] = html.NameFor(expression).ToString();
    tag.Attributes["value"] = "true";

    // set the "checked" attribute if true
    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
    if (metadata.Model != null)
    {
        bool modelChecked;
        if (Boolean.TryParse(metadata.Model.ToString(), out modelChecked))
        {
            if (modelChecked)
            {
                tag.Attributes["checked"] = "checked";
            }
        }
    }

    // merge custom attributes
    tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));

    var tagString = tag.ToString(TagRenderMode.SelfClosing);
    return MvcHtmlString.Create(tagString);
}

그것은 비슷 크리스 켐프 이 하나를 제외하고는 잘 작동됩니다의 방법, 사용하지 않는 기본 CheckBoxForRegex.Replace. 원래 Html.CheckBoxFor방법 의 출처를 기반으로합니다 .


이것은이 문제에 대한 최상의 솔루션이며 MVC 프레임 워크의 일부 여야합니다 ... 완벽하게 작동합니다. 귀하의 답변이 더 많은 관심을받지 못한 이유는 확실하지 않습니다 ... 감사합니다!
user2315985

@ user2315985 : 조금 늦게 게시했습니다.) 그 이유입니다.
Tom Pažourek

컬렉션 속성을 어떻게 처리하고 있습니까? 기본 모델 바인더는 바운드 인덱스에 틈이 생길 때 바인딩 값을 중지하므로 확장을 사용하는 것처럼 보입니다. 예를 들어 첫 번째 값과 마지막 값을 확인한 경우 두 번째 값을 알 수 없습니다 . 아니면 뭔가 빠졌습니까?
Tieson T.

@TiesonT. 자체 모델 바인더를 작성하지 않는 한 유일한 해결책은 간격을 방지하는 것입니다. 이 메소드는 체크되지 않은 체크 박스에 대해 false를 보내지 않으므로 그렇게하는 원래 Html.CheckBoxFor 메소드를 사용할 수 있습니다.
Tom Pažourek

10

추가 입력 태그 의 소스 코드는 다음과 같습니다 . Microsoft는이 문제를 정확하게 해결하는 의견을 포함시킬만큼 친절했습니다.

if (inputType == InputType.CheckBox)
{
    // Render an additional <input type="hidden".../> for checkboxes. This
    // addresses scenarios where unchecked checkboxes are not sent in the request.
    // Sending a hidden input makes it possible to know that the checkbox was present
    // on the page when the request was submitted.
    StringBuilder inputItemBuilder = new StringBuilder();
    inputItemBuilder.Append(tagBuilder.ToString(TagRenderMode.SelfClosing));

    TagBuilder hiddenInput = new TagBuilder("input");
    hiddenInput.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.Hidden));
    hiddenInput.MergeAttribute("name", fullName);
    hiddenInput.MergeAttribute("value", "false");
    inputItemBuilder.Append(hiddenInput.ToString(TagRenderMode.SelfClosing));
    return MvcHtmlString.Create(inputItemBuilder.ToString());
}

9

가장 간단한 해결책은 다음과 같이 INPUT 요소를 직접 렌더링하는 것입니다.

<input type="checkbox" 
       id="<%=Html.IdFor(i => i.ReceiveRSVPNotifications)%>"
       name="<%=Html.NameFor(i => i.ReceiveRSVPNotifications)%>"
       value="true"
       checked="<%=Model.ReceiveRSVPNotifications ? "checked" : String.Empty %>" />

Razor 구문에서는 'true'서버 측 값이 주어지면 'checked'속성이 "checked"값으로 직접 렌더링되므로 훨씬 더 쉽습니다.

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