Tại sao CheckBoxFor hiển thị thẻ đầu vào bổ sung và làm cách nào tôi có thể nhận được giá trị bằng FormCollection?


130

Trong ứng dụng ASP.NET MVC của tôi, tôi kết xuất hộp kiểm bằng mã sau:

<%= Html.CheckBoxFor(i=>i.ReceiveRSVPNotifications) %>

Bây giờ, tôi thấy rằng điều này biểu hiện cả thẻ đầu vào hộp kiểm và thẻ đầu vào ẩn. Vấn đề mà tôi gặp phải là khi tôi thử truy xuất giá trị từ hộp kiểm bằng FormCollection:

FormValues["ReceiveRSVPNotifications"]

Tôi nhận được giá trị "đúng, sai". Khi nhìn vào HTML được kết xuất, tôi có thể thấy như sau:

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

Vì vậy, bộ sưu tập FormValues ​​dường như tham gia hai giá trị này vì chúng có cùng tên.

Bất kỳ ý tưởng?

Câu trả lời:


168

Có một cái nhìn ở đây:

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

Đây không phải là một lỗi và trên thực tế là cách tiếp cận tương tự mà cả Ruby on Rails và MonoRail đều sử dụng.

Khi bạn gửi biểu mẫu với hộp kiểm, giá trị chỉ được đăng nếu hộp kiểm được chọn. Vì vậy, nếu bạn bỏ chọn hộp kiểm thì sẽ không có gì được gửi đến máy chủ khi trong nhiều tình huống bạn muốn gửi sai. Vì đầu vào ẩn có cùng tên với hộp kiểm, nên nếu bỏ chọn hộp kiểm, bạn vẫn sẽ nhận được 'sai' gửi đến máy chủ.

Khi hộp kiểm được chọn, ModelBinder sẽ tự động trích xuất 'true' từ 'true, false'


10
Đó là một lời giải thích tốt nhưng trong một số trường hợp, bạn có thể muốn nhận được 'không có gì' trong chuỗi truy vấn khi ckecbox không được kiểm tra - vì vậy hành vi mặc định. Điều này có thể sử dụng trình trợ giúp Html hay tôi chỉ đơn giản là sử dụng <input>thẻ.
Thiếu tá Maksymilian

13
Tôi không thích điều này .... Tôi có một trang tìm kiếm sử dụng GET và bây giờ url của tôi chứa đầy thông số đúng / sai ...
Shawn Mclean

1
Wow, thật bất ngờ. Điều này có nghĩa là hộp kiểm HTML thực sự bị "hỏng"?
Isantipov

1
@Isantipov: Không, điều đó chỉ có nghĩa là các khung web này không dựa vào việc không có giá trị được đăng cho một hộp kiểm để chỉ ra false. Hãy xem câu trả lời của RyanJMcGowan bên dưới: "Gửi một đầu vào ẩn giúp có thể biết rằng hộp kiểm đã có mặt trên trang khi yêu cầu được gửi."
Robert Harvey

1
Chà @Robert, cái này không hiệu quả với tôi. Nếu chbox tôi MyCheckbox không được chọn sau đó tôi nhận sai, khi MyCheckbox được kiểm tra sau đó tôi nhận được một mảng của [đúng, sai] như giá trị của nó. Tôi đang tuần tự hóa toàn bộ biểu mẫu và chuyển nó qua ajax cho hành động của bộ điều khiển, vd. AddToOrder (mô hình MyModel) nơi tôi nhận mô hình.MyCheckbox = false thay vì true
nickornotto

18

Tôi đã có cùng một vấn đề như Shawn (ở trên). Cách tiếp cận này có thể là tuyệt vời cho POST, nhưng nó thực sự hấp dẫn cho GET. Do đó, tôi đã triển khai một phần mở rộng Html đơn giản, chỉ cần đánh bật trường ẩn.

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

Vấn đề bây giờ tôi gặp phải là tôi không muốn thay đổi khung MVC để phá mã của mình. Vì vậy, tôi phải đảm bảo tôi có bảo hiểm thử nghiệm giải thích hợp đồng mới này.


5
Anh không cảm thấy một chút bẩn mà bạn sử dụng regex để phù hợp / loại bỏ các đầu vào ẩn thay vì chỉ xây dựng chỉ một đầu vào checkbox? :)
Tim Hobbs

2
Không, tôi đã làm điều đó để tôi sửa đổi hành vi hiện có, thay vì thực hiện lại hành vi của mình. Bằng cách đó, sự thay đổi của tôi sẽ theo kịp với bất kỳ thay đổi nào mà MS đưa ra.
Chris Kemp

10
Chỉ là một quan sát nhỏ. Việc triển khai của bạn sẽ không hiển thị bất kỳ thuộc tính tùy chỉnh nào được thông qua. Tham số "htmlAttribut" không được truyền cho phương thức "CheckBoxFor" ban đầu.
Emil Lundin

16

Tôi sử dụng phương pháp thay thế này để hiển thị các hộp kiểm cho biểu mẫu 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);
}

Nó tương tự như phương pháp của Chris Kemp , đang hoạt động tốt, ngoại trừ phương pháp này không sử dụng cơ bản CheckBoxForRegex.Replace. Nó dựa trên nguồn gốc của Html.CheckBoxForphương thức ban đầu .


Đây hoàn toàn là giải pháp tốt nhất cho vấn đề này và nên là một phần của khung MVC ... nó hoạt động hoàn hảo. Tôi không chắc tại sao câu trả lời của bạn không được chú ý nhiều hơn ... cảm ơn!
dùng2315985

@ user2315985: Tôi đã đăng nó hơi muộn một chút;) đó là lý do.
Tom Pažourek

Làm thế nào bạn xử lý các thuộc tính bộ sưu tập? Chất kết dính mô hình mặc định sẽ dừng các giá trị ràng buộc khi nó gặp một khoảng trống trong các chỉ mục bị ràng buộc, do đó, có vẻ như sử dụng tiện ích mở rộng của bạn, nếu, giả sử, các giá trị đầu tiên và cuối cùng đã được kiểm tra, bạn sẽ không bao giờ biết về giá trị thứ hai bạn sẽ nhận được . Hoặc, tôi đang thiếu một cái gì đó?
Tieson T.

@TiesonT. Trừ khi bạn muốn viết chất kết dính mô hình của riêng bạn, giải pháp duy nhất là ngăn chặn các khoảng trống. Phương thức này không gửi sai cho các hộp kiểm không được kiểm tra, vì vậy bạn có thể muốn sử dụng phương thức Html.CheckBoxFor ban đầu thực hiện điều đó.
Tom Pažourek

10

Đây là mã nguồn cho thẻ đầu vào bổ sung. Microsoft đã rất tử tế khi đưa vào những bình luận giải quyết vấn đề này một cách chính xác.

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

9

Tôi nghĩ rằng giải pháp đơn giản nhất là kết xuất trực tiếp phần tử INPUT như sau:

<input type="checkbox" 
       id="<%=Html.IdFor(i => i.ReceiveRSVPNotifications)%>"
       name="<%=Html.NameFor(i => i.ReceiveRSVPNotifications)%>"
       value="true"
       checked="<%=Model.ReceiveRSVPNotifications ? "checked" : String.Empty %>" />

Trong cú pháp Dao cạo thậm chí còn dễ dàng hơn, bởi vì thuộc tính 'đã kiểm tra' được hiển thị trực tiếp với giá trị "đã kiểm tra" khi được cung cấp giá trị phía máy chủ 'đúng'.

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.