5

CheckBoxFor is not bounded when a property is defined in an object nested in the model?

Here is an example. I have a SearchOptions model that contains a List<Star> property. Each Star has a number, a name and a bool property that should be bounded:

public class SearchOptions
{

    public SearchOptions()
    {
        // Default values
        Stars = new List<Star>()
        {
            new Star() {Number=1, Name=Resources.Home.Index.Star1,
                IsSelected=false},
            new Star() {Number=2, Name=Resources.Home.Index.Star2,
                IsSelected=false},
            new Star() {Number=3, Name=Resources.Home.Index.Star3,
                IsSelected=true},
            new Star() {Number=4, Name=Resources.Home.Index.Star4,
                IsSelected=true},
            new Star() {Number=5, Name=Resources.Home.Index.Star5,
                IsSelected=true},
        };
    }

    public List<Star> Stars { get; set; }

}

In my strongly typed View (of SearchOptions) i loop over Stars property:

@using (Html.BeginForm("Do", "Home"))
{
    <fieldset>
        <legend>@MVC3TestApplication.Resources.Home.Index.Search</legend>
        @{ 
            foreach (Star s in Model.Stars)
           {
                @Html.CheckBoxFor(m => s.IsSelected)
                <label>@s.Name</label>

           }}
    </fieldset>
    <input type=submit value="Invia" />
}

The (relevant part of) controller is:

    public ActionResult SearchOptions()
    {
        return View(new SearchOptions());
    }

    [HttpPost]
    public ActionResult Do(SearchOptions s)
    {
        // Do some stuff
        return View("SearchOptions", s);
    }
3
  • Your code looks fine - What is actually wrong? Are you passing in the model via View(model)? Commented Jul 21, 2011 at 19:46
  • Do (SearchOptions s) shows that s has old (default) values, even if i check/uncheck all the checkboxes. Thanks for helping, Commented Jul 21, 2011 at 19:48
  • Ah. In that case the reason is because of the nested properties. The output of CheckBoxFor() sets it's name values to s.IsSelected rather than Model.Star[].IsSelected. I'll see what I can do or someone else will post the answer before me :) Commented Jul 21, 2011 at 19:53

1 Answer 1

8

It's because of how you're accessing the properties in the CheckBoxFor expression.

@for (int i = 0; i < Model.Stars.Count(); i++) { 
    @Html.CheckBoxFor(m => m.Stars[i].IsSelected)
    <label>@Model.Stars[i].Name</label>
}

This should work for you.

Here's the output from the different methods:

//using the for loop
<input id="Stars_2__IsSelected" name="Stars[2].IsSelected" type="checkbox" value="true" />

//using the foreach
<input checked="checked" id="s_IsSelected" name="s.IsSelected" type="checkbox" value="true" />

You'll notice that the for foreach doesn't contain the proper name for it to match to when doing model binding.

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

4 Comments

Works. But there is an odd problem: after POST labels gets an empty value. I've just used <label> without bounding Model.Stars[i].Name to some input field. Do you know why? Edit: solved using Html.HiddenFor. But is this the right way? It's quite a paint to write one HiddenFor for each property of the object to bind...
The reason is that the Html helpers use the post values from the list items. Because the post values are null for the Name property they will be empty when reused (since they'll override the default values). I'm not sure off hand what you can do other than repopulate the names and numbers before output.
As far as I know it won't work on list or array properties, I could be wrong.
Is there a way to do this with a foreach loop instead of a for loop?

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.