asp.net mvc: tại sao Html.CheckBox tạo ra một đầu vào ẩn bổ sung


215

Tôi chỉ nhận thấy rằng Html.CheckBox("foo")tạo ra 2 đầu vào thay vì một, có ai biết tại sao lại như vậy không?

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

3
có thể trùng lặp phương thức
Matt

1
Câu trả lời của ericvg trong câu hỏi trùng lặp có thể cũng giải thích những gì chất kết dính mô hình làm khi cả hộp kiểm và trường ẩn được gửi.
Theophilus

1
Tôi ghét điều này nó đang ồ ạt với trò đùa của tôi.
Jerry Liang

2
Thực hiện kỳ ​​lạ bởi mvc. Gửi cả hai giá trị không có ý nghĩa gì cả. Tôi đã kiểm tra Request.From ["myCheckBox"] và giá trị của nó là đúng, sai. WTF. Tôi đã phải viết điều khiển bằng tay trong chế độ xem.
Nick Masao

Nếu điều này thực sự không mong muốn thì đừng sử dụng Html.CheckBox (...) và chỉ cần nhập html cho hộp kiểm
wnbates

Câu trả lời:


197

Nếu hộp kiểm không được chọn, trường biểu mẫu sẽ không được gửi. Đó là lý do tại sao luôn có giá trị sai trong trường ẩn. Nếu bạn bỏ chọn hộp kiểm, biểu mẫu sẽ vẫn có giá trị từ trường ẩn. Đó là cách ASP.NET MVC xử lý các giá trị hộp kiểm.

Nếu bạn muốn xác nhận điều đó, hãy đặt một hộp kiểm vào biểu mẫu không phải bằng Html.Hidden, nhưng với <input type="checkbox" name="MyTestCheckboxValue"></input>. Bỏ chọn hộp kiểm, gửi biểu mẫu và xem các giá trị yêu cầu được đăng ở phía máy chủ. Bạn sẽ thấy rằng không có giá trị hộp kiểm. Nếu bạn có trường ẩn, nó sẽ chứa MyTestCheckboxValuemục có falsegiá trị.


52
Nếu bạn không chọn hộp thì rõ ràng câu trả lời là sai, không cần nó gửi lại hàng. Thiết kế ngớ ngẩn theo ý kiến ​​của tôi.
Người đàn ông Muffin

54
@TheMuffinMan: Đây không phải là lựa chọn ngớ ngẩn. Hãy nói rằng mô hình khung nhìn của bạn có thuộc tính được gọi IsActive, được khởi tạo truetrong hàm tạo. Người dùng bỏ chọn hộp kiểm, nhưng vì giá trị không được gửi đến máy chủ, nên chất kết dính mô hình không nhận nó và giá trị thuộc tính không thay đổi. Chất kết dính mô hình không nên cho rằng, nếu giá trị không được gửi, nó được đặt thành false, vì đó có thể là quyết định của bạn không gửi giá trị này.
LukLed

21
Nó bắt đầu với một hộp kiểm vô hại và sau đó trước khi bạn biết nó, chúng ta có trạng thái xem sau đó nó phát triển thành ASP.NET MVCForms.
Người đàn ông Muffin

4
@LukLed Trả lời bình luận của bạn muộn ... Tôi nghĩ rằng logic đó là thiếu sót bởi vì nếu mô hình chế độ xem của bạn có kiểu thuộc tính int và không có đầu vào trên biểu mẫu thì giá trị mặc định là 0 vì không có giá trị nào thay đổi. Tương tự với bất kỳ thuộc tính nào khác, giá trị mặc định cho chuỗi là null. Nếu bạn không gửi một giá trị thì nó là null. Trong ví dụ của bạn về việc đặt một thuộc tính thành true trong hàm tạo, đó thực sự là một quyết định thiết kế tồi và bây giờ nó được đưa ra ánh sáng vì cách các hộp kiểm hoạt động trong vùng đất http.
Người đàn ông Muffin

8
Logic đổ bóng này phá vỡ các hộp kiểm bị vô hiệu hóa - chúng gửi falsegiá trị ngay cả khi chúng được chọn và điều đó gây nhầm lẫn. Các hộp kiểm bị vô hiệu hóa hoàn toàn không nên gửi bất kỳ giá trị nào, nếu ASP.NET muốn tương thích với hành vi HTTP mặc định.
JustAMartin

31

Bạn có thể viết một trình trợ giúp để ngăn chặn việc thêm đầu vào ẩn:

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

sử dụng nó:

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

4
Điều này làm tôi vấp ngã trong một phút vì vậy chỉ trong trường hợp ... Nếu người trợ giúp của bạn ở trong một không gian tên đừng quên thêm @using Your.Name.Spacevào đầu tệp xem dao cạo .cshtml của bạn.
ooXei1sh 24/07/2015

3
@ ooXei1sh Hoặc là hoặc đặt người trợ giúp của bạn vào không gian tên System.Web.Mvc.Htmlđể có thể truy cập được trên tất cả các chế độ xem
Luke

1
Nếu bạn muốn sử dụng điều này cho một postback hoặc để đăng qua ajax với các giá trị của biểu mẫu thì bạn sẽ cần xử lý cài đặt giá trị thành true hoặc false thông qua sự kiện onchange trên hộp kiểm. @ Html.CheckBoxSimple (x => Model.Foo, new {value = Model.Foo, onchange = "toggleCheck (this)"}). Sau đó, trong hàm javascript ToggleCompleted (el) {var đã kiểm tra = $ (el) .is (': đã kiểm tra'); $ ('# Foo'). Val (đã chọn); }
John81

12

khi hộp kiểm được chọn và gửi thực hiện việc này

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

Tham khảo


8

Cách tiếp cận thủ công là thế này:

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

1
Và điều này có được đảm bảo để giúp bạn có được giá trị loại hộp kiểm chứ không phải giá trị loại ẩn không?
Brian Sweeney

1
điều đó không liên quan Khi hộp kiểm không được chọn, nó không đăng. Vì vậy, hộp ẩn sẽ có 'sai'. Nếu hộp kiểm được chọn, giá trị của 'true, true' được trả về (tôi nghĩ) và điều này không bằng 'false'.
Valamas

16
Không, khi hộp kiểm được chọn, cả đúng và sai đều được đăng vì cả hộp kiểm và trường ẩn đều là các điều khiển hợp lệ được gửi lại. Chất kết dính Mvc sau đó kiểm tra xem giá trị thực có tồn tại cho một tên cụ thể không và nếu có thì nó thích giá trị thực hơn. Bạn có thể kiểm tra điều này bằng cách xem dữ liệu được đăng. Nó sẽ có cả giá trị đúng và sai so với tên đơn.
ZafarYousafi

Điều này đã cho tôi một lần, tôi đang kiểm tra xem giá trị == true
Terry Kernan

8

Đây là phiên bản được đánh máy mạnh mẽ của giải pháp của 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

Sử dụng Chứa, nó sẽ hoạt động với hai giá trị bài có thể: "false" hoặc "true, false".

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

1

Các đầu vào ẩn đã gây ra vấn đề với các hộp kiểm theo kiểu. Vì vậy, tôi đã tạo tiện ích mở rộng Trình trợ giúp Html để đặt đầu vào ẩn bên ngoài div có chứa CheckBox.

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

Kết quả

<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

Đây không phải là một lỗi! Nó bổ sung khả năng luôn có một giá trị, sau khi đăng mẫu lên máy chủ. Nếu bạn muốn xử lý các trường nhập hộp kiểm với jQuery, hãy sử dụng phương thức prop (chuyển thuộc tính 'đã kiểm tra' làm tham số). Thí dụ:$('#id').prop('checked')


0

Bạn có thể thử khởi tạo hàm tạo của Mô hình của mình như thế:

public MemberFormModel() {
    foo = true;
}

và theo quan điểm của bạn:

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

0

Tôi thấy điều này thực sự gây ra vấn đề khi tôi có một WebGrid. Các liên kết sắp xếp trên WebGrid sẽ biến chuỗi truy vấn tăng gấp đôi hoặc x = true & x = false thành x = true, false và gây ra lỗi phân tích cú pháp trong hộp kiểm cho.

Tôi đã kết thúc bằng cách sử dụng jQuery để xóa các trường ẩn ở phía máy khách:

    <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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.