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

내 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 ​​컬렉션은 이름이 같기 때문에이 두 값을 결합하는 것으로 보입니다.

어떤 아이디어?



답변

여기를보세요 :

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

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

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

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


답변

나는 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 프레임 워크를 변경하고 싶지 않다는 것입니다. 따라서이 새로운 계약을 설명하는 테스트 범위가 있는지 확인해야합니다.


답변

이 대체 방법을 사용하여 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방법 의 출처를 기반으로합니다 .


답변

추가 입력 태그 의 소스 코드는 다음과 같습니다 . 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());
}


답변

가장 간단한 해결책은 다음과 같이 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”값으로 직접 렌더링되므로 훨씬 더 쉽습니다.


답변