Acabei de perceber que Html.CheckBox("foo")
gera 2 entradas em vez de uma, alguém sabe por que isso acontece?
<input id="foo" name="foo" type="checkbox" value="true" />
<input name="foo" type="hidden" value="false" />
Acabei de perceber que Html.CheckBox("foo")
gera 2 entradas em vez de uma, alguém sabe por que isso acontece?
<input id="foo" name="foo" type="checkbox" value="true" />
<input name="foo" type="hidden" value="false" />
Respostas:
Se a caixa de seleção não estiver selecionada, o campo do formulário não será enviado. É por isso que sempre há um valor falso no campo oculto. Se você deixar a caixa de seleção desmarcada, o formulário ainda terá valor do campo oculto. É assim que o ASP.NET MVC lida com os valores das caixas de seleção.
Se você quiser confirmar isso, marque a caixa de seleção não com Html.Hidden, mas com <input type="checkbox" name="MyTestCheckboxValue"></input>
. Deixe a caixa de seleção desmarcada, envie o formulário e observe os valores de solicitação publicados no lado do servidor. Você verá que não há valor na caixa de seleção. Se você tivesse um campo oculto, ele conteria MyTestCheckboxValue
entrada com false
valor.
IsActive
, que é iniciada true
no construtor. O usuário desmarca a caixa de seleção, mas como o valor não é enviado ao servidor, o fichário do modelo não a seleciona e o valor da propriedade não é alterado. O fichário do modelo não deve assumir que, se o valor não for enviado, ele foi definido como falso, pois pode ser sua decisão de não enviar esse valor.
false
valor mesmo se estiverem marcadas e isso é confuso. As caixas de seleção desabilitadas não devem enviar nenhum valor, se o ASP.NET quiser ser compatível com o comportamento HTTP padrão.
Você pode escrever um auxiliar para evitar adicionar a entrada oculta:
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);
}
}
use-o:
@Html.CheckBoxSimple("foo", new {value = bar.Id})
@using Your.Name.Space
das dúvidas ... Se o seu ajudante estiver em um espaço para nome, não se esqueça de adicionar no topo do seu arquivo de visualização .cshtml.
System.Web.Mvc.Html
para ser acessível em todos os pontos de vista
A abordagem manual é esta:
bool IsDefault = (Request.Form["IsDefault"] != "false");
Esta é a versão fortemente tipada da solução de 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);
}
}
A entrada oculta estava causando problemas nas caixas de seleção com estilo. Então, criei uma extensão auxiliar de HTML para colocar a entrada oculta fora da div que contém a caixa de seleção.
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());
}
Resultado
<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">
Isso não é um bug! Acrescenta a possibilidade de sempre ter um valor, depois de postar o formulário no servidor. Se você quiser lidar com os campos de entrada da caixa de seleção com jQuery, use o método prop (passe a propriedade 'marcada' como parâmetro). Exemplo:$('#id').prop('checked')
Você pode tentar inicializar o construtor do seu modelo assim:
public MemberFormModel() {
foo = true;
}
e na sua opinião:
@html.Checkbox(...)
@html.Hidden(...)
Descobri que isso realmente causava problemas quando eu tinha um WebGrid. Os links de classificação no WebGrid girariam pela string de consulta dobrada ou x = true & x = false em x = true, false e causariam um erro de análise na caixa de seleção.
Acabei usando o jQuery para excluir os campos ocultos no lado do cliente:
<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>