Почему CheckBoxFor отображает дополнительный входной тег и как я могу получить значение с помощью FormCollection? - PullRequest
127 голосов
/ 19 мая 2010

В моем приложении 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, кажется, объединяет эти два значения, поскольку они имеют одно и то же имя.

Любые идеи?

Ответы [ 5 ]

168 голосов
/ 19 мая 2010

Посмотрите здесь:

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

Это не ошибка, и на самом деле это тот же подход, что и на Ruby Rails и MonoRail используют.

Когда вы отправляете форму с флажком, значение публикуется только в том случае, если флажок установлен. Итак, если вы оставите флажок снятым, то ничего не будет отправлено на сервер, когда во многих ситуациях вы бы хотите, чтобы вместо этого было отправлено false. Поскольку скрытый ввод имеет то же имя в качестве флажка, то если флажок снят, вы все равно получите 'false' отправлено на сервер.

Когда флажок установлен, ModelBinder автоматически примет уход за извлечением «истинного» из «истинного, ложного» * ​​1011 *

17 голосов
/ 12 марта 2012

У меня была та же проблема, что и у Шона (см. Выше). Этот подход может быть полезен для 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-структуре нарушало мой код. Поэтому я должен убедиться, что у меня есть тестовое покрытие, объясняющее этот новый контракт.

14 голосов
/ 31 мая 2015

Я использую этот альтернативный метод для рендеринга флажков для форм 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);
}

Это похоже на метод Криса Кемпа , который работает нормально, за исключением того, что не использует базовые CheckBoxFor и Regex.Replace. Он основан на источнике оригинального метода Html.CheckBoxFor.

10 голосов
/ 03 мая 2013

Вот исходный код для дополнительного тега ввода. 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());
}
7 голосов
/ 19 апреля 2015

Я думаю, что самое простое решение - визуализировать элемент 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 это даже проще, потому что атрибут 'checked' напрямую отображается со значением 'selected', когда ему присваивается 'true' значение на стороне сервера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...