asp.net mvc: Html.CheckBox neden ek bir gizli girdi oluşturuyor?


215

Sadece bir Html.CheckBox("foo")yerine 2 giriş oluşturduğunu fark ettim , herkes bunun neden böyle olduğunu biliyor mu?

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


1
ericvg'nin olası yinelenen sorudaki yanıtı , hem onay kutusu hem de gizli alanlar gönderildiğinde model bağlayıcının ne yaptığını da açıklar.
Theophilus

1
Benim jquery ile toplu bu şeyden nefret ediyorum.
Jerry Liang

2
Mvc tarafından garip uygulama. Her iki değeri de göndermek hiç mantıklı değil. Request.From ["myCheckBox"] 'ı kontrol ettim ve değeri doğru, yanlıştı. O NE LAN. Görünümü manuel olarak kontrol etmek zorunda kaldım.
Nick Masao

Bu gerçekten istenmeyen ise, o zaman Html.CheckBox (...) kullanmayın ve sadece bir onay kutusu için html girin
wnbates

Yanıtlar:


198

Onay kutusu seçilmezse form alanı gönderilmez. Bu yüzden gizli alanda her zaman yanlış değer vardır. Onay kutusunu işaretlemezseniz formun gizli alandan değeri yine de olur. ASP.NET MVC onay kutusu değerlerini bu şekilde işler.

Bunu onaylamak istiyorsanız, Html.Hidden ile değil, ile forma bir onay kutusu yerleştirin <input type="checkbox" name="MyTestCheckboxValue"></input>. Onay kutusunu işaretlemeyin, formu gönderin ve sunucu tarafında yayınlanan istek değerlerine bakın. Onay kutusu değeri olmadığını göreceksiniz. Gizli alanınız olsaydı MyTestCheckboxValue, falsedeğer içeren bir girdi içerirdi.


52
Kutuyu işaretlemediyseniz, cevap kesinlikle yanlıştır, öğeyi geri göndermesine gerek yoktur. Bence aptal tasarım.
Muffin Adam

54
@TheMuffinMan: Bu aptalca bir seçenek değil. Görünüm modelinizin yapıcıda IsActivebaşlatılan bir özelliğe sahip olduğunu varsayalım true. Kullanıcı onay kutusunun seçimini kaldırır, ancak değer sunucuya gönderilmediğinden, model bağlayıcı onu almaz ve özellik değeri değişmez. Model bağlayıcı, değer gönderilmezse yanlış olarak ayarlandığını varsaymamalıdır, çünkü bu değeri göndermemeye karar verebilirsiniz.
LukLed

21
Zararsız bir onay kutusuyla başlar ve siz görmeden önce görünüm durumumuz vardır, o zaman ASP.NET MVCForms'a dönüşür.
Muffin Man

4
@LukLed Yorumunuza geç cevap veriyoruz ... Bence manken kusurludur, çünkü görünüm modelinizde bir özellik türü int varsa ve formda herhangi bir girdi yoksa, varsayılan değer 0'dır, çünkü değiştirmek için herhangi bir değer gelmedi. Aynı şey başka herhangi bir özellik için de geçerli, bir dize için varsayılan değer null. Bir değer göndermezseniz, bu boştur. Yapıcıda bir özelliği true olarak belirleme örneğinizde, bu dürüstçe kötü bir tasarım kararıdır ve http arazisinde onay kutularının nasıl çalıştığı nedeniyle artık ortaya çıkmaktadır.
Muffin Man

8
Bu gölgeleme mantığı devre dışı bırakılmış onay kutuları için kesilir - işaretlenmiş olsalar falsebile değer gönderirler ve bu kafa karıştırıcıdır. ASP.NET varsayılan HTTP davranışı ile uyumlu olmak istiyorsa, devre dışı bırakılmış onay kutuları hiçbir değer göndermemelidir.
JustAMartin

31

Gizli girdinin eklenmesini önlemek için bir yardımcı yazabilirsiniz:

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

kullanın:

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

4
Bu durum beni bir dakika kadar tetikledi, her ihtimale karşı… Yardımcınız bir ad alanındaysa @using Your.Name.Space.cshtml tıraş bıçağı görünüm dosyanızın üstüne eklemeyi unutmayın .
ooXei1sh

3
@ ooXei1sh Ya bu, ya da yardımınızı System.Web.Mvc.Htmltüm görünümlerde erişilebilir olması için ad alanına koyun
Luke

1
Bunu bir form geri gönderimi için veya form değerleriyle ajax aracılığıyla göndermek için kullanmak istiyorsanız, onay kutusundaki onchange olayı aracılığıyla değeri true veya false olarak ayarlamanız gerekir. @ Html.CheckBoxSimple (x => Model.Foo, yeni {value = Model.Foo, onchange = "toggleCheck (this)"}). Sonra javascript fonksiyonunda ToggleCompleted (el) {var ekose = $ (el) .is (': ekli'); $ ( '# Foo') val (işaretli).; }
John81

12

onay kutusu işaretlendiğinde ve gönderildiğinde bunu gerçekleştirin

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

başvurmak


8

Manuel yaklaşım şudur:

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

1
Ve bunun, gizli tür değerini değil, onay kutusu tür değerini alması garanti edilir mi?
Brian Sweeney

1
bu alakasız. Onay kutusu işaretli olmadığında posta gönderilmez. Böylece gizli kutuda 'yanlış' olacaktır. Onay kutusu işaretlenirse 'true, true' değeri döndürülür (sanırım) ve bu 'false' değerine eşit değildir.
Valamas

16
Hayır, onay kutusu işaretlendiğinde, hem onay kutusu hem de gizli alanlar geri gönderilecek geçerli kontroller olduğundan hem doğru hem de yanlış gönderilir. Mvc bağlayıcı daha sonra belirli bir namve için true değerinin olup olmadığını kontrol eder ve eğer öyleyse gerçek değeri tercih eder. Kaydedilen verileri görüntüleyerek bunu kontrol edebilirsiniz. Tek bir isme karşı hem doğru hem de yanlış değerlere sahip olacaktır.
ZafarYousafi

Bu beni bir kez yakaladı, değeri == doğru olup olmadığını kontrol ediyordum
Terry Kernan

8

Bu, Alexander Trofimov'un çözümünün güçlü bir şekilde yazılmış versiyonudur:

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

İçerir'i kullanın, iki olası yazı değeriyle çalışır: "false" veya "true, false".

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

1

Gizli girdi, stil onay kutuları ile sorunlara neden oluyordu. Bu yüzden gizli girişi CheckBox içeren div dışında yerleştirmek için bir Html Yardımcı Uzantısı oluşturdum.

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

Sonuç

<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

Bu bir hata değil! Formu sunucuya gönderdikten sonra her zaman bir değere sahip olma olasılığını ekler. JQuery ile onay kutusu giriş alanlarıyla ilgilenmek istiyorsanız, prop yöntemini kullanın (parametre olarak 'işaretli' özelliğini iletin). Misal:$('#id').prop('checked')


0

Modelinizin yapıcısını şu şekilde başlatmayı deneyebilirsiniz:

public MemberFormModel() {
    foo = true;
}

ve sizin görüşünüze göre:

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

0

Bir WebGrid vardı bu gerçekten sorunlara neden bulundu. WebGrid'deki sıralama bağlantıları iki kat yukarı sorgu dizesi veya x = true & x = false değerinin x = true, false değerine döneceğini ve onay kutusunda ayrıştırma hatasına neden olacağını belirtiyor.

İstemci tarafında gizli alanları silmek için jQuery kullanarak sona erdi:

    <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>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.