Je viens de remarquer que Html.CheckBox("foo")
génère 2 entrées au lieu d'une, tout le monde sait pourquoi en est-il ainsi?
<input id="foo" name="foo" type="checkbox" value="true" />
<input name="foo" type="hidden" value="false" />
Je viens de remarquer que Html.CheckBox("foo")
génère 2 entrées au lieu d'une, tout le monde sait pourquoi en est-il ainsi?
<input id="foo" name="foo" type="checkbox" value="true" />
<input name="foo" type="hidden" value="false" />
Réponses:
Si la case n'est pas cochée, le champ du formulaire n'est pas soumis. C'est pourquoi il y a toujours une fausse valeur dans un champ caché. Si vous ne cochez pas la case, le formulaire aura toujours la valeur du champ masqué. Voilà comment ASP.NET MVC gère les valeurs des cases à cocher.
Si vous souhaitez confirmer cela, cochez une case sur le formulaire non pas avec Html.Hidden, mais avec <input type="checkbox" name="MyTestCheckboxValue"></input>
. Ne cochez pas la case, soumettez le formulaire et examinez les valeurs de demande publiées côté serveur. Vous verrez qu'il n'y a pas de valeur de case à cocher. Si vous aviez un champ caché, il contiendrait une MyTestCheckboxValue
entrée avec une false
valeur.
IsActive
, qui est initiée true
dans le constructeur. L'utilisateur désélectionne la case à cocher, mais comme la valeur n'est pas envoyée au serveur, le classeur de modèle ne la récupère pas et la valeur de la propriété n'est pas modifiée. Le classeur de modèles ne doit pas supposer que si la valeur n'est pas envoyée, elle est définie sur false, car il pourrait être votre décision de ne pas envoyer cette valeur.
false
valeur même si elles sont cochées, ce qui est déroutant. Les cases à cocher désactivées ne doivent pas envoyer de valeur du tout, si ASP.NET veut être compatible avec le comportement HTTP par défaut.
Vous pouvez écrire un assistant pour empêcher l'ajout de l'entrée masquée:
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);
}
}
utilise le:
@Html.CheckBoxSimple("foo", new {value = bar.Id})
@using Your.Name.Space
en haut de votre fichier de vue de rasoir .cshtml.
System.Web.Mvc.Html
de noms pour qu'il soit accessible sur toutes les vues
L'approche manuelle est la suivante:
bool IsDefault = (Request.Form["IsDefault"] != "false");
Voici la version fortement typée de la solution d'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);
}
}
L'entrée masquée causait des problèmes avec les cases à cocher stylisées. J'ai donc créé une extension d'assistance HTML pour placer l'entrée cachée en dehors de la div contenant la 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());
}
Résultat
<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">
Ce n'est pas un bug! Il ajoute la possibilité d'avoir toujours une valeur, après avoir posté le formulaire sur le serveur. Si vous souhaitez traiter les champs de saisie de case à cocher avec jQuery, utilisez la méthode prop (passez la propriété 'checked' comme paramètre). Exemple:$('#id').prop('checked')
Vous pouvez essayer d'initialiser le constructeur de votre modèle comme ça:
public MemberFormModel() {
foo = true;
}
et selon vous:
@html.Checkbox(...)
@html.Hidden(...)
J'ai trouvé que cela causait vraiment des problèmes lorsque j'avais un WebGrid. Les liens de tri sur le WebGrid tourneraient par la chaîne de requête doublée ou x = true & x = false en x = true, false et provoqueraient une erreur d'analyse dans la case à cocher pour.
J'ai fini par utiliser jQuery pour supprimer les champs cachés côté client:
<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>