2

I'm working on ASP.NET MVC web application, and I need to submit List<ProdColor> to Controller using checkboxs. Here is my code

Model

public partial class ProdColor
{
    public int ProdColor_ID { get; set; }
    public Nullable<int> P_ID { get; set; }
    public Nullable<int> Color_ID { get; set; }

    public virtual ProdctModelView ProdctModelView { get; set; }
}

public class ProdctModelView
{
    public ProdctModelView()
    {
        this.ProductColors = new HashSet<ProdColor>();
    }

    public int P_ID { get; set; }
    public string P_name { get; set; }

    public virtual ICollection<ProdColor> ProductColors { get; set; }
}

Controller

public ActionResult Create()
{
    ViewBag.colorlist = db.Colors.OrderBy(m => m.Color_name).ToList();
    return View();
}

[HttpPost]
public ActionResult Create(ProdctModelView product, List<ProdColor> ProductColors)
{
    Product prod = new Product();
    //Save new product
    db.Products.Add(prod);
    db.SaveChanges();

    foreach (var color in ProductColors)
    {        
        color.P_ID = prod.P_ID;
        db.ProdColors.Add(color);
     }
     db.SaveChanges();
     return RedirectToAction("Index");
}

View

@model mvc4test.Models.ProdctModelView
@using (Html.BeginForm("Create", "CP_Product", FormMethod.Post))
{

    @for (int i = 0; i < ViewBag.colorlist.Count; i++)
    {                      
        <input type="checkbox" id="@ViewBag.colorlist[i].Color_name" name="[@i].Color_ID" value="@ViewBag.colorlist[i].Color_id"/>
    }
    <input type="submit" value="Save" />
}

The problem is when submitting the checkboxes without selecting the first one, the value of List<ProdColor> become Null. So how should I get the correct values at the Controller.

mariam hossam
  • 31
  • 1
  • 1
  • 3
  • Welcome to SO. Does this existing question help you ? http://stackoverflow.com/questions/220020/how-to-handle-checkboxes-in-asp-net-mvc-forms?rq=1 – Fabske Oct 03 '15 at 13:22

1 Answers1

13

You manually creating checkboxes with indexers. Unchecked checkboxes do not post back a value, so if any of the checkboxes are unchecked, you get non-consecutive indexers so model binding fails.

Your model (view model) needs to include a boolean property (say) public bool IsSelected { get; set; } so that in the view you can use the @Html.CheckBoxFor() method to strongly bind to your model.

@for (int i = 0; i < Model.ColorList.Count; i++)
{
    @Html.HiddenFor(m => m.ColorList[i].Color_id)
    @Html.CheckBoxFor(m => m.ColorList[i].IsSelected)
    @Html.LabelFor(m => m.ColorList[i].IsSelected, Model.ColorList[i].Color_name)
}

The CheckBoxFor() method generates a checkbox with value="true" and an associated hidden input with value="false". If the checkbox is checked, both true and false are posted, but only the first (true) value is bound. If the checkbox is unchecked, the only false is posted.

Then in the POST method, you can get the ID's of the selected items using (say)

var selectedColors = product.ColorList.Where(c => c.IsSelected).Select(c => c.Color_id);

Note that you do not need a parameter in your POST method for List<ProdColor> ProductColors since parameter ProdctModelView product already contains all those values.

  • This was immensely helpful when dealing with multiple rows of check boxes in a single form. The classic technique of indexing didn't bind the array correctly when the first checkbox wasn't selected, so breaking it out like this was the way to go – Ben Sewards Dec 10 '15 at 20:55