asp.net mvc:为什么Html.CheckBox生成附加的隐藏输入


215

我只是注意到Html.CheckBox("foo")生成了2个输入而不是一个,所以有人知道为什么会这样吗?

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


1
ericvg在可能存在的重复问题中的答案还解释了同时提交复选框和隐藏字段时,模型绑定程序的作用。
Theophilus

1
我讨厌这个东西在我的jquery中流行。
杰里·梁

2
通过mvc奇怪的实现。发送这两个值根本没有任何意义。我检查了Request.From [“ myCheckBox”],其值为true,false。WTF。我必须在视图中手动编写控件。
Nick Masao 2015年

如果确实不希望这样做,则不要使用Html.CheckBox(...),而只需输入html作为复选框
wnbates

Answers:


197

如果未选中该复选框,则不会提交表单字段。这就是为什么隐藏字段中始终存在错误值的原因。如果未选中此复选框,则窗体仍将具有来自隐藏字段的值。这就是ASP.NET MVC处理复选框值的方式。

如果要确认这一点,请在不使用Html.Hidden而是使用的表单上放置一个复选框<input type="checkbox" name="MyTestCheckboxValue"></input>。取消选中该复选框,提交表单并查看服务器端已发布的请求值。您会看到没有复选框值。如果您有隐藏字段,它将包含MyTestCheckboxValue带有false值的条目。


52
如果您没有选中该框,那么答案显然是错误的,不需要它发回该物品。我认为愚蠢的设计。
松饼人

54
@TheMuffinMan:这不是愚蠢的选择。假设您的视图模型具有名为的属性IsActive,该属性true在构造函数中初始化。用户取消选择复选框,但是由于未将值发送到服务器,因此模型绑定程序不会选择它,并且属性值不会更改。模型绑定器不应假定,如果未发送值,则将其设置为false,因为您可以决定不发送该值。
LukLed 2014年

21
它以无害的复选框开始,然后在您知道它具有视图状态之前,它就演变为ASP.NET MVCForms。
松饼人2015年

4
@LukLed稍后回复您的评论...我认为逻辑上存在缺陷,因为如果您的视图模型具有属性类型int,并且表单上没有输入,则默认值为0,因为没有值可以更改它。其他任何属性都一样,字符串的默认值为null。如果不发送值,则为null。坦白说,在构造函数中将属性设置为true的示例中,这确实是一个错误的设计决定,并且由于复选框在http land中的工作方式而变得很明显。
松饼人

8
这种阴影逻辑破坏了禁用复选框的作用- false即使选中了复选框,它们也会发送值,这令人困惑。如果ASP.NET希望与默认HTTP行为兼容,则禁用的复选框完全不应发送任何值。
JustAMartin

31

您可以编写一个帮助程序来防止添加隐藏的输入:

using System.Web.Mvc;
using System.Web.Mvc.Html;

public static class HelperUI
{
    public static MvcHtmlString CheckBoxSimple(this HtmlHelper htmlHelper, string name, object htmlAttributes)
    {
        string checkBoxWithHidden = htmlHelper.CheckBox(name, htmlAttributes).ToHtmlString().Trim();
        string pureCheckBox = checkBoxWithHidden.Substring(0, checkBoxWithHidden.IndexOf("<input", 1));
        return new MvcHtmlString(pureCheckBox);
    }
}

用它:

@Html.CheckBoxSimple("foo", new {value = bar.Id})

4
这让我绊了一分钟,以防万一...如果您的助手在命名空间中,请不要忘记@using Your.Name.Space在.cshtml剃刀视图文件的顶部添加。
ooXei1sh 2015年

3
@ ooXei1sh要么将您的助手放入System.Web.Mvc.Html所有视图中都可以访问的名称空间中
路加福音

1
如果要将此用于表单回发或通过带有表单值的Ajax进行发布,则需要通过复选框上的onchange事件处理将值设置为true或false。@ Html.CheckBoxSimple(x => Model.Foo,新的{value = Model.Foo,onchange =“ toggleCheck(this)”})。然后在javascript函数ToggleCompleted(el){varchecked = $(el).is(':checked'); $('#Foo')。val(选中); }
John81 '18

12

选中并提交复选框后,执行此操作

if ($('[name="foo"]:checked').length > 0)
    $('[name="foo"]:hidden').val(true);

参考


8

手动方法是这样的:

bool IsDefault = (Request.Form["IsDefault"] != "false");

1
并保证可以为您提供复选框类型值,而不是隐藏类型值吗?
Brian Sweeney 2012年

1
那无关紧要。如果未选中该复选框,则不会发布。因此,hiddenbox将具有“ false”。如果选中此复选框,则返回“ true,true”的值(我认为),这不等于“ false”。
Valamas 2012年

16
不,当选中复选框时,将同时发布true和false,因为checkbox和hidden字段都是要发送回的有效控件。然后,Mvc联编程序检查给定的剪裁是否存在真值,如果是,则选择真值。您可以通过查看过帐的数据进行检查。针对单个名称,它将同时具有true和false值。
ZafarYousafi 2013年

这让我知道了一次,我正在检查值是否== true
Terry Kernan 2014年

8

这是Alexander Trofimov解决方案的强类型版本:

using System.Web.Mvc;
using System.Web.Mvc.Html;

public static class HelperUI
{
    public static MvcHtmlString CheckBoxSimpleFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool>> expression, object htmlAttributes)
    {
        string checkBoxWithHidden = htmlHelper.CheckBoxFor(expression, htmlAttributes).ToHtmlString().Trim();
        string pureCheckBox = checkBoxWithHidden.Substring(0, checkBoxWithHidden.IndexOf("<input", 1));
        return new MvcHtmlString(pureCheckBox);
    }
}

4

使用“包含”,它将使用两个可能的过帐值:“ false”或“ true,false”。

bool isChecked = Request.Form["foo"].Contains("true");

1

隐藏的输入导致样式复选框出现问题。因此,我创建了一个HTML Helper Extension,以将隐藏的输入放置在包含CheckBox的div之外。

using System;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;

namespace YourNameSpace
{
    public static class HtmlHelperExtensions
    {
        public static MvcHtmlString CustomCheckBoxFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, string labelText)
        {
            //get the data from the model binding
            var fieldName = ExpressionHelper.GetExpressionText(expression);
            var fullBindingName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(fieldName);
            var fieldId = TagBuilder.CreateSanitizedId(fullBindingName);
            var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            var modelValue = metaData.Model;

            //create the checkbox
            TagBuilder checkbox = new TagBuilder("input");
            checkbox.MergeAttribute("type", "checkbox");
            checkbox.MergeAttribute("value", "true"); //the visible checkbox must always have true
            checkbox.MergeAttribute("name", fullBindingName);
            checkbox.MergeAttribute("id", fieldId);

            //is the checkbox checked
            bool isChecked = false;
            if (modelValue != null)
            {
                bool.TryParse(modelValue.ToString(), out isChecked);
            }
            if (isChecked)
            {
                checkbox.MergeAttribute("checked", "checked");
            }

            //add the validation
            checkbox.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(fieldId, metaData));

            //create the outer div
            var outerDiv = new TagBuilder("div");
            outerDiv.AddCssClass("checkbox-container");

            //create the label in the outer div
            var label = new TagBuilder("label");
            label.MergeAttribute("for", fieldId);
            label.AddCssClass("checkbox");

            //render the control
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(outerDiv.ToString(TagRenderMode.StartTag));
            sb.AppendLine(checkbox.ToString(TagRenderMode.SelfClosing));
            sb.AppendLine(label.ToString(TagRenderMode.StartTag));
            sb.AppendLine(labelText); //the label
            sb.AppendLine("<svg width=\"10\" height=\"10\" class=\"icon-check\"><use xlink:href=\"/icons.svg#check\"></use></svg>"); //optional icon
            sb.AppendLine(label.ToString(TagRenderMode.EndTag));
            sb.AppendLine(outerDiv.ToString(TagRenderMode.EndTag));

            //create the extra hidden input needed by MVC outside the div
            TagBuilder hiddenCheckbox = new TagBuilder("input");
            hiddenCheckbox.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.Hidden));
            hiddenCheckbox.MergeAttribute("name", fullBindingName);
            hiddenCheckbox.MergeAttribute("value", "false");
            sb.Append(hiddenCheckbox.ToString(TagRenderMode.SelfClosing));

            //return the custom checkbox
            return MvcHtmlString.Create(sb.ToString());
        }

结果

<div class="checkbox-container">
    <input checked="checked" id="Model_myCheckBox" name="Model.myCheckBox" type="checkbox" value="true">
    <label class="checkbox" for="Model_myCheckBox">
        The checkbox label
        <svg width="10" height="10" class="icon-check"><use xlink:href="/icons.svg#check"></use></svg>
    </label>
</div>
<input name="Model.myCheckBox" type="hidden" value="false">

0

这不是错误!在将表单发布到服务器后,它增加了始终具有值的可能性。如果要使用jQuery处理复选框输入字段,请使用prop方法(将'checked'属性作为参数传递)。例:$('#id').prop('checked')


0

您可以尝试像这样初始化Model的构造函数:

public MemberFormModel() {
    foo = true;
}

并且在您看来:

@html.Checkbox(...)
@html.Hidden(...)

0

当我拥有WebGrid时,我发现这确实引起了问题。WebGrid上的排序链接将查询字符串加倍或x = true&x = false变成x = true,false,并在复选框中引起解析错误。

我最终使用jQuery删除了客户端的隐藏字段:

    <script type="text/javascript">
    $(function () {
        // delete extra hidden fields created by checkboxes as the grid links mess this up by doubling the querystring parameters
        $("input[type='hidden'][name='x']").remove();
    });
    </script>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.