asp.net mvc:为什么 Html.CheckBox 会生成一个额外的隐藏输入

问题描述 投票:0回答:13
asp.net-mvc checkbox hidden-field
13个回答
218
投票

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

如果您想确认这一点,请在表单上放置一个复选框,而不是使用 Html.Hidden,而是使用

<input type="checkbox" name="MyTestCheckboxValue"></input>
。取消选中复选框,提交表单并查看服务器端发布的请求值。您会看到没有复选框值。如果您有隐藏字段,它将包含具有
MyTestCheckboxValue
值的
false
条目。


35
投票

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

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

15
投票

从 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


13
投票

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

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

参考


9
投票

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

8
投票

手动方法是这样的:

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

5
投票

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

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

2
投票

截至 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);
}

1
投票

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

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
投票

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

public MemberFormModel() {
    foo = true;
}

在您看来:

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

0
投票

在 .Net core 6 中,我遇到了同样的问题,我尝试了@Kolazomai 的回答并且它正在工作。

using Microsoft.AspNetCore.Mvc;

builder.Services.Configure<MvcViewOptions>(
opt=>opt.HtmlHelperOptions.CheckBoxHiddenInputRenderMode = Microsoft.AspNetCore.Mvc.Rendering.CheckBoxHiddenInputRenderMode.None
);
© www.soinside.com 2019 - 2024. All rights reserved.