MVC Model Binding with Checkbox list....possibly haunted

94 Views Asked by At

I have a viewmodel with a list of objects which I'm rendering as checkboxes with the MVC CheckboxFor() helper like so:

@Html.CheckBoxFor(x => x.OrganisationDetails.Industries[i].Checked)

When the HTML renders, I get the standard double output which all appears as it should be:

<input id="OrganisationDetails_Industries_0__Checked" name="OrganisationDetails.Industries[0].Checked" type="checkbox" value="true">
<input name="OrganisationDetails.Industries[0].Checked" type="hidden" value="false">

When I look at the HTTP headers that are posted, I see the values set correctly for the checkbox I've ticked:

OrganisationDetails.Industries[3].Checked:true
OrganisationDetails.Industries[3].Checked:false

However, when I get back into C# and examine the model parameter of the POST action which received the form, the value is always bound as false.

I'm aware of many many other questions which skirt around this issue, but most say that when the HTTP form values are posted as above, the model binder should handle it, in my case however it's not.

I've ensured there are no other fields on the form, no hiddens kicking about, no custom model binding configs etc etc.

Everything else in other areas of the form binds OK, just not the checkboxes.

Is it because they are nested in a child class? does the property Checked conflict with an HTML property during post? I'm serious stumped here and about to revert to not using the helper.

I'm posting here because I don't believe that the helper is fundamentally broken, so I'd like to understand what I've done wrong!

EDIT: Here is the model (abridged for brevity) and controller action if it's any help.

**model classes**

public class Industry
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool Checked { get; set; }
}

public class OrganisationDetails 
{
    [Required]
    [Display(Name = "Industry", Description = "Select all that apply")]
    public List<Industry> Industries = new List<Industry>
    {
        new Industry { Id = 1, Name = "Industry 1" },
        new Industry { Id = 2, Name = "Industry 2" },
        new Industry { Id = 3, Name = "Industry 3" },
        new Industry { Id = 4, Name = "Industry 4" }
    };        
}


public class TheViewModel 
{
    public OrganisationDetails { get; set; }
}

**controller action**

    [HttpPost]
    [Route("OrganisationDetails/Part/{id}")]
    public ActionResult OrganisationDetails(int id, TheViewModel model)
    {
        // breakpoint is on this line, model.OrganisationDetails.Industries are all shown with 'Checked = false'
        // this is where I was about to write the persistance code, but the model values aren't correct for this collection, so there is nothing in here.
        return RedirectToAction($"OrganisationDetails/Part/{id + 1}");
    }
0

There are 0 best solutions below