asp.net mvc:Html.CheckBoxが追加の非表示入力を生成する理由


215

Html.CheckBox("foo")1つではなく2つの入力を生成することに気づきましたが、なぜこれがそうなのか誰もが知っていますか?

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


1
重複する可能性のある質問に対するericvgの回答は、チェックボックスと非表示フィールドの両方が送信された場合のモデルバインダーの動作も説明しています。
Theophilus

1
私はそれが私のjqueryで大量になっていたのが嫌いです。
Jerry Liang、

2
mvcによる奇妙な実装。両方の値を送信しても、まったく意味がありません。Request.From ["myCheckBox"]をチェックしたところ、その値はtrue、falseでした。WTF。ビューでコントロールを手動で記述する必要がありました。
Nick Masao

これが本当に望ましくない場合は、Html.CheckBox(...)を使用せずに、チェックボックスのhtmlを入力してください
wnbates

回答:


197

チェックボックスが選択されていない場合、フォームフィールドは送信されません。そのため、隠しフィールドには常に偽の値があります。チェックボックスをオフのままにしても、フォームには非表示フィールドの値が残ります。これがASP.NET MVCがチェックボックスの値を処理する方法です。

それを確認したい場合は、Html.Hiddenではなくでフォームにチェックボックスを配置します<input type="checkbox" name="MyTestCheckboxValue"></input>。チェックボックスをオフのままにして、フォームを送信し、サーバー側で投稿されたリクエスト値を確認します。チェックボックスの値がないことがわかります。非表示のフィールドがある場合はMyTestCheckboxValuefalse値を持つエントリが含まれます。


52
チェックボックスをオンにしなかった場合、答えは明らかにfalseで、アイテムを返送する必要はありません。私の考えでは愚かなデザインです。
マフィンマン

54
@TheMuffinMan:これはばかげたオプションではありません。ビューモデルにと呼ばれるプロパティIsActiveがありtrue、コンストラクタで開始されているとします。ユーザーはチェックボックスの選択を解除しますが、値はサーバーに送信されないため、モデルバインダーはそれを取得せず、プロパティ値は変更されません。モデルバインダーは、値が送信されない場合はfalseに設定されていると想定しないでください。これは、この値を送信しないことを決定できるためです。
LukLed 2014

21
それは無害なチェックボックスから始まり、それからそれがわかる前にビューステートがあるので、ASP.NET MVCFormsに進化します。
マフィンマン

4
@LukLedコメントへの返信が遅い...ビューモデルにプロパティタイプintがあり、フォームに入力がない場合、デフォルト値は0なので、変更するための値がないため、ロジックに欠陥があると思います。同じことが他のプロパティにも当てはまります。文字列のデフォルト値はnullです。値を送信しない場合はnullです。コンストラクターでプロパティをtrueに設定する例では、これは正直なところ、設計上の悪い決定であり、httpランドでチェックボックスがどのように機能するかが原因で明らかになります。
マフィンマン

8
このシャドウロジックは、無効になっているチェックボックスfalseでは機能しません。チェックされていても値を送信するため、混乱を招きます。ASP.NETがデフォルトのHTTP動作との互換性を必要とする場合、無効化されたチェックボックスは値を送信しないでください。
JustAMartin

31

非表示の入力を追加しないようにするヘルパーを作成できます。

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

4
これ@using Your.Name.Spaceにより、念のため1分間つまづきました。ヘルパーが名前空間にいる場合は、忘れずに.cshtmlかみそりビューファイルの先頭に追加してください。
ooXei1sh 2015

3
@ ooXei1shどちらか、またはSystem.Web.Mvc.Htmlすべてのビューでアクセスできるようにヘルパーを名前空間に配置します
Luke

1
これをフォームポストバックに使用する場合、またはフォームの値を使用して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(チェック済み); }
John81 2018

12

チェックボックスがチェックされて送信されると、これを実行します

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

参照


8

手動のアプローチはこれです:

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

1
そして、これは非表示のタイプの値ではなく、チェックボックスタイプの値を取得することが保証されていますか?
ブライアンスウィーニー

1
それは無関係です。チェックボックスがチェックされていない場合、投稿しません。したがって、hiddenboxは「false」になります。チェックボックスがチェックされている場合、「true、true」の値が返され(私はそう思います)、これは「false」と等しくありません。
Valamas

16
いいえ、チェックボックスをオンにすると、チェックボックスと非表示フィールドの両方が送り返される有効なコントロールであるため、trueとfalseの両方が送信されます。Mvcバインダーは、指定されたnamveにtrue値が存在するかどうかを確認し、存在する場合はtrue値を優先します。投稿されたデータを見ることで確認できます。単一の名前に対してtrueとfalseの両方の値を持ちます。
ZafarYousafi 2013年

これは私に1度手に入れました、私は値== trueかどうかをチェックしていました
Terry Kernan

8

これは、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

Containsを使用すると、 "false"または "true、false"の2つの可能なポスト値で機能します。

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

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

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>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.