0

I've read and implemented many answers here and around the web but had no luck..

My model looks something like this:

public class CampaignModel : BaseModel
{
    .
    .
    public List<TreeItem> Countries { get; set; }
    .
    .
}

In the view i have:

@foreach (var country in Model.Countries.Select((value,i)=> new {i, value}))
{
<input type="checkbox" name="campaign.Countries[@country.i].Id" value="@country.value.Id" @(country.value.IsSelected ? "checked=\"checked\"" : "") />
}

At the action I have:

[HttpPost]
public ActionResult UpdateTargeting(CampaignModel campaign)
{
    return View(campaign);
}

But the 'Countries' property turns out null.

What am I doing wrong? Thank you

2
  • You don't need the campaign. prefix in the name of the checkboxes. Commented Dec 29, 2013 at 13:42
  • Can you give the detail of TreeItem class , i think this is not getting intialized.Try doing that in the constructor Commented Dec 29, 2013 at 14:21

2 Answers 2

3

First I think you need to use Model instead of campaign in the name attributes, like below:

name="@Model.Countries[@country.i].Id"

And right now your foreach loop will generate the html code like below:

<input type="checkbox" name="1" value="1"/>
<input type="checkbox" name="2" value="2" checked=""checked""/>

With above code, the model binding will not work, that's why you got null values when you submitted the form. You need something like below:

<input id="Countries_0__IsSelected" name="Countries[0].IsSelected" type="checkbox" value="true"/>
<input name="Countries[0].IsSelected" type="hidden" value="false"/>
<input checked="checked" id="Countries_1__IsSelected" name="Countries[1].IsSelected" type="checkbox" value="true"/>
<input name="Countries[1].IsSelected" type="hidden" value="false"/>

So I suggest you to use Razor syntax, like below:

foreach (var country in Model.Countries.Select((value,i)=> new {i, value}))
{
      @Html.CheckBoxFor(m => m.Countries[@country.i].IsSelected )    
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Lin, what you wrote helped me come out with the solution below!
Note to others who tried this: doesn't work for IEnumerable or ICollection of Countries, only on List or Array
0

I ended up adding 2 more hidden fields to identify the exact checkbox.

The TreeItem lolks like this:

public class TreeItem
{
    public int Id { get; set; }
    public string Title { get; set; }
    public bool IsSelected { get; set; }
    public List<TreeItem> Leafes { get; set; }

    public TreeItem() { }

    public TreeItem(int id, string title, bool selected = false, List<TreeItem> leafes = null)
    {
        Id = id;
        Title = title;
        IsSelected = selected;
        Leafes = leafes;
    }
}

The full solution looks like this (I demonstrate a a 2 level hierarchy):

<ul id="devicesList">
    @foreach (var brand in Model.DeviceBrands.Select((value, i) => new { i, value }))
    { 
                    <li>
                        @Html.CheckBoxFor(m => m.DeviceBrands[@brand.i].IsSelected)
                        @Html.HiddenFor(m => m.DeviceBrands[@brand.i].Id)
                        @Html.HiddenFor(m => m.DeviceBrands[@brand.i].Title)
                        <label><b>@brand.value.Title</b></label>
                        <ul>
                            @foreach (var deviceModel in brand.value.Leafes.Select((value, j) => new { j, value }))
                            {
                                <li>
                                    @Html.CheckBoxFor(m => m.DeviceBrands[@brand.i].Leafes[@deviceModel.j].IsSelected)
                                    @Html.HiddenFor(m => m.DeviceBrands[@brand.i].Leafes[@deviceModel.j].Id)
                                    @Html.HiddenFor(m => m.DeviceBrands[@brand.i].Leafes[@deviceModel.j].Title)
                                    <label>@deviceModel.value.Title</label>
                                </li>
                            }
                        </ul>
                    </li>
    }
</ul>

Thanks Lin!

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.