1

I have a field called W2_Sent which is defined as (bit,null)

In my view I have the following which shows it as a checkbox:

     <div class="editor-label"  style="width: 10em">                        
       @Html.Label("W2 Sent")
     </div>
     <div class="editor-field">
       @Html.EditorFor(model => model.W2_Sent)
       @Html.ValidationMessageFor(model => model.W2_Sent)
     </div>

If I check it, I get an error

The value 'checked' is not valid for W2_Sent

      [HttpPost]
      public ActionResult Create(Employee emp)
      {

        foreach (ModelState modelState in ViewData.ModelState.Values)
        {
            foreach (ModelError error in modelState.Errors)
            {

                string s = "error";

            }

        }

I am able to trap the error within the foreach loop you see above..

Why am I getting value 'checked' is invalid though

7
  • 1
    Does @Html.CheckboxFor(model => model.W2_Sent) make a difference? Commented Jul 25, 2012 at 18:09
  • What does the W2_Sent editor template look like? Commented Jul 25, 2012 at 18:10
  • When I changed it to @Html.CheckboxFor, I get teh following:Cannot implicitly convert type 'bool?' to 'bool'. An explicit conversion exists (are you missing a cast?) Commented Jul 25, 2012 at 18:11
  • It's (bit, null) in the database (I assume), but what is it in the model object you're binding? Commented Jul 25, 2012 at 18:13
  • I am binding to @model Lopt.Areas.Emp.Models.Employee Commented Jul 25, 2012 at 18:14

3 Answers 3

12

For displaying checkboxes in forms you should always use @Html.CheckBox/CheckBoxFor instead of <input type="checkbox" name="gender" />. When you use @Html.CheckBox/CheckBoxFor ASP.NET MVC generates a hidden field which has a boolean value and that is what will be binded to your model property.

When you directly use the html part then browsers posts the value of the field as string "checked" if it is, and in model binding that throws the error.

Sign up to request clarification or add additional context in comments.

Comments

4

I've done it like this. Write your own ExtensionMethod for CheckBoxFor. The trick is the static values for "value" = "true" in the checkbox and the "value" "false" in the hidden field. As mentioned before, a checkbox with a value false will not be sent back. In this case the value of the hidden field will be taken. When the checkbox is checked by the user, the new "true"-value will override the "false" from the hidden field.

    public static MvcHtmlString CheckboxForMetro<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, int offset = 3)
    {
        TagBuilder tblabel = new TagBuilder("label");
        tblabel.AddCssClass("checkbox offset" + offset.ToString());

        TagBuilder tbinput = new TagBuilder("input");
        tbinput.Attributes.Add("type", "checkbox");
        tbinput.Attributes.Add("id", GetPropertyNameFromLambdaExpression(html, expression));
        tbinput.Attributes.Add("name", GetPropertyNameFromLambdaExpression(html, expression));
        tbinput.Attributes.Add("value", "true");
        tbinput.MergeAttributes(GetPropertyValidationAttributes(html, expression, null));
        if (GetPropertyValueFromLambdaExpression(html, expression) == "True") tbinput.Attributes.Add("checked", "checked");

        TagBuilder tbhidden = new TagBuilder("input");
        tbhidden.Attributes.Add("type", "hidden");
        tbhidden.Attributes.Add("value", "false");
        tbhidden.Attributes.Add("name", GetPropertyNameFromLambdaExpression(html, expression));

        TagBuilder tbspan = new TagBuilder("span");
        //tbspan.AddCssClass("span" + spanLabel.ToString());
        tbspan.InnerHtml = GetPropertyDisplayNameFromLambdaExpression(html, expression);
        tblabel.InnerHtml = tbinput.ToString() + tbspan.ToString() + tbhidden.ToString();

        return new MvcHtmlString(tblabel.ToString());
    }

It's an ExtensionMethod for the Metro UI CSS at http://metroui.org.ua

This is the code for getting the value, displayname, propertyname and validationAttributes

    private static string GetPropertyDisplayNameFromLambdaExpression<TModel, TValue>(HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        string htmlFieldName = ExpressionHelper.GetExpressionText(expression);

        return metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last() ?? "Geen tekst";
    }

    private static string GetPropertyValueFromLambdaExpression<TModel, TValue>(HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
    {
        string value = string.Empty;
        TModel model = html.ViewData.Model;
        if (model != null)
        {
            var expr = expression.Compile().Invoke(model);
            if (expr != null)
            {
                value = expr.ToString();
            }
        }
        return value;
    }

    private static string GetPropertyNameFromLambdaExpression<TModel, TValue>(HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        return metadata.PropertyName;
    }

    private static IDictionary<string, object> GetPropertyValidationAttributes<TModel, TValue>(HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        IDictionary<string, object> validationAttributes = html.GetUnobtrusiveValidationAttributes(ExpressionHelper.GetExpressionText(expression), metadata);
        if (htmlAttributes == null)
        {
            htmlAttributes = validationAttributes;
        }
        else
        {
            htmlAttributes = htmlAttributes.Concat(validationAttributes).ToDictionary(k => k.Key, v => v.Value);
        }
        return htmlAttributes;
    }

I hope this will help someone else.

Comments

0

In my case, I was using some styling library that did not allow me to use the HTMLhelper. So, if it is useful for anyone, a straightforward solution was using jQuery when submitting the form, simply assigning the check value to the input, as shown below.

$("#myForm").submit(function (e) {
    $("#myCheckBoxInput").val($("#myCheckBoxInput").prop("checked"))
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.