【问题标题】:asp.net mvc: why is Html.CheckBox generating an additional hidden inputasp.net mvc:为什么 Html.CheckBox 会生成额外的隐藏输入
【发布时间】:2011-02-11 10:37:13
【问题描述】:

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

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

【问题讨论】:

  • ericvg's answer 在可能的重复问题中还解释了在提交复选框和隐藏字段时模型绑定器的作用。
  • 我讨厌它在我的 jquery 中堆积的这个东西。
  • mvc 的奇怪实现。发送这两个值根本没有意义。我检查了 Request.From["myCheckBox"] ,它的值为真,假。哇。我不得不在视图中手动编写控件。
  • 如果这真的不受欢迎,那么不要使用 Html.CheckBox(...) 并且只需输入 html 的复选框

标签: asp.net-mvc


【解决方案1】:

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

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

【讨论】:

  • 如果您没有选中该框,那么显然答案是错误的,无需将项目退回。我认为愚蠢的设计。
  • @TheMuffinMan:这不是愚蠢的选择。假设您的视图模型具有名为IsActive 的属性,该属性在构造函数中初始化为true。用户取消选中复选框,但由于值未发送到服务器,模型绑定器不会拾取它,并且属性值不会更改。模型绑定器不应假设,如果未发送值,则将其设置为 false,因为您可能决定不发送此值。
  • 它以一个无害的复选框开始,然后在你知道它之前我们有视图状态,然后它演变成 ASP.NET MVCForms。
  • @LukLed 回复你的评论晚了......我认为这个逻辑是有缺陷的,因为如果你的视图模型有一个属性类型 int 并且表单上没有输入,那么默认值为 0 因为没有价值通过改变它。任何其他属性也是如此,字符串的默认值为空。如果您不发送值,则为空。在您在构造函数中将属性设置为 true 的示例中,这确实是一个糟糕的设计决策,现在由于复选框在 http 领域中的工作方式而曝光。
  • 这种阴影逻辑会破坏禁用的复选框 - 即使它们被选中,它们也会发送 false 值,这令人困惑。如果 ASP.NET 希望与默认 HTTP 行为兼容,则禁用的复选框根本不应该发送任何值。
【解决方案2】:

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

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

【讨论】:

  • 这让我一时不爽,所以以防万一...如果您的助手位于命名空间中,请不要忘记在 .cshtml razor 视图文件的顶部添加 @using Your.Name.Space
  • @ooXei1sh 要么,或者将你的助手放在命名空间System.Web.Mvc.Html 以便在所有视图上都可以访问
  • 如果您想将其用于表单回发或通过带有表单值的 ajax 发布,那么您需要通过复选框上的 onchange 事件将值设置为 true 或 false。 @Html.CheckBoxSimple(x => Model.Foo, new {value = Model.Foo, onchange = "toggleCheck(this)" })。然后在 javascript 函数 ToggleCompleted(el) { var checked = $(el).is(':checked'); $('#Foo').val(选中); }
【解决方案3】:

当复选框被选中并提交时执行此操作

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

Refer

【讨论】:

    【解决方案4】:

    这是 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);
        }
    }
    

    【讨论】:

      【解决方案5】:

      手动方法是这样的:

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

      【讨论】:

      • 这能保证得到复选框类型值而不是隐藏类型值吗?
      • 这无关紧要。当复选框未选中时,它不会发布。所以隐藏框会有'假'。如果选中复选框,则返回“真,真”的值(我认为),这不等于“假”。
      • 不,当复选框被选中时,true 和 false 都会被发布,因为复选框和隐藏字段都是要发回的有效控件。 Mvc binder 然后检查给定的 namve 是否存在真值,如果存在,它更喜欢真值。您可以通过查看发布的数据来检查这一点。对于单个名称,它将具有真值和假值。
      • 这得到了我一次,我正在检查值是否 == true
      【解决方案6】:

      从 ASP.NET (Core) 5 开始,将其添加到您的 Startup:

      services.Configure<MvcViewOptions>(options =>
      {
          // Disable hidden checkboxes
          options.HtmlHelperOptions.CheckBoxHiddenInputRenderMode = CheckBoxHiddenInputRenderMode.None;
      });
      

      以你的观点为例:

      <input class="form-check-input" asp-for="@Model.YourBool" />
      

      不再在您的表单中创建此属性的附加隐藏字段:

      <input class="form-check-input" type="checkbox" data-val="true" data-val-required="The YourBool field is required." id="YourBool" name="YourBool" value="true" />
      

      来源: https://github.com/dotnet/aspnetcore/pull/13014#issuecomment-674449674

      【讨论】:

        【解决方案7】:

        使用包含,它将与两个可能的帖子值一起使用:“false”或“true,false”。

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

        【讨论】:

        • 如果最初设置了复选框怎么办?隐藏字段将包含“true”,不是吗?
        【解决方案8】:

        当我有一个 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>
        

        【讨论】:

          【解决方案9】:

          截至 2020/11 和 .NET 5 处于预览阶段,有一个 pull request 应该可以控制此行为。谢谢各位!

          无论如何,如果有人觉得它有用,Alexander Trofimov 的答案的 .NET Core 3.0 端口:

          public static IHtmlContent CheckBoxSimple(this IHtmlHelper htmlHelper, string name)
          {
              TextWriter writer = new StringWriter();
          
              IHtmlContent html = htmlHelper.CheckBox(name);
              html.WriteTo(writer, HtmlEncoder.Default);
          
              string checkBoxWithHidden = writer.ToString();
          
              string pureCheckBox = checkBoxWithHidden.Substring(0, checkBoxWithHidden.IndexOf("<input", 1));
              return new HtmlString(pureCheckBox);
          }
          

          【讨论】:

            【解决方案10】:

            隐藏的输入导致样式复选框出现问题。所以我创建了一个 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">
            

            【讨论】:

              【解决方案11】:

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

              【讨论】:

                【解决方案12】:

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

                public MemberFormModel() {
                    foo = true;
                }
                

                在你看来:

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-07-24
                  • 1970-01-01
                  • 2011-05-28
                  • 2011-09-20
                  • 2011-08-21
                  • 1970-01-01
                  • 2021-11-07
                  • 2012-07-07
                  相关资源
                  最近更新 更多