Reputation: 1382
I am using the Entity Framework and I have a many to many relationship between Products and Categories. I have created my models and they seemed to have created the tables correctly. Now I am trying to insert a product and am getting the error: "Value cannot be null." on the line: @Html.ListBoxFor(model => model.ProductCategories, Model.CategorySelectList.Select(c => new SelectListItem { Text = c.Text, Value = c.Value }), new { @class = "chzn-select", data_placeholder = "Choose categorie(s)..."})
Here is my ProductModel:
public class ProductModel
{
public int ID { get; set; }
[Required(ErrorMessage = "Required")]
[Index("ItemNumber", 1, IsUnique = true)]
[Display(Name = "Item #")]
public int itemNumber { get; set; }
[Required(ErrorMessage = "Required")]
[Display(Name = "Product")]
[MaxLength(50)]
public String product { get; set; }
[Display(Name = "Description")]
[MaxLength(500)]
public String description { get; set; }
[DefaultValue(true)]
[Display(Name = "Active?")]
public bool active { get; set; }
[Display(Name = "Image Name")]
public String imageName { get; set; }
[Display(Name = "PDF Name")]
public String PDFName { get; set; }
[Display(Name = "Category(s)")]
public virtual ICollection<CategoryModel> ProductCategories { get; set; }
public IEnumerable<SelectListItem> CategorySelectList { get; set; }
//public ICollection<CategoryModel> CategoryList { get; set; }
public virtual BrochureModel Brochure { get; set; }
public IEnumerable<SelectListItem> BrochureList { get; set; }
public static IEnumerable<SelectListItem> getCategories(int id = 0)
{
using (var db = new ProductContext())
{
List<SelectListItem> list = new List<SelectListItem>();
var categories = db.Categories.ToList();
foreach (var cat in categories)
{
SelectListItem sli = new SelectListItem { Value = cat.ID.ToString(), Text = cat.categoryName };
if (id > 0 && cat.ID == id)
{
sli.Selected = true;
}
list.Add(sli);
}
return list;
}
}
public ProductModel()
{
active = true;
}
}
Here is the method in the controller that populates the lists:
public ActionResult ControlPanel()
{
ViewBag.Message = TempData["Message"] == null ? "" : TempData["Message"].ToString();
//using (var db = new ProductContext())
//{
// var categories = from c in db.Categories
// select c;
// categories = categories.OrderByDescending(c => c.isActive);
// var model = new AdminModel
// {
// Categories = categories.ToList(),
// Products = db.Products.ToList(),
// RegisterUsers = db.RegisterViewModels.ToList()
// };
// return View(model);
//}
var model = new AdminModel();
using (var db = new ProductContext())
{
var categories = from c in db.Categories
select c;
categories = categories.OrderByDescending(c => c.isActive);
model.Categories = categories.ToList();
model.Products = db.Products.ToList();
model.Brochures = db.Brochures.ToList();
};
I probably have something wrong in the ListBoxFor line and maybe something wrong in my model too, but I'm not sure.
Upvotes: 0
Views: 1108
Reputation:
Property model.ProductCategories
is ICollection<CategoryModel>
. You cannot bind a <select multiple>
to a collection of complex objects, only a collection of value types. Assuming Category.ID
is typeof int
then your model needs a property (say)
public int[] SelectedCategories { get; set; } // or List<int>
and then in the view
@Html.ListBoxFor(m => m.SelectedCategories, Model.CategorySelectList, new { @class = "chzn-select", data_placeholder = "Choose categorie(s)..."})
In you POST method, SelectedCategories
will then contain the selected category ID's.
Note also Model.CategorySelectList
is already IEnumerable<SelectListItem>
so creating a new IEnumerable<SelectListItem>
from it (as you are doing with .Select(c => new SelectListItem { Text = c.Text, Value = c.Value })
is just pointless extra overhead.
In addition the following code in your getCategories()
method is also pointless.
if (id > 0 && cat.ID == id) { sli.Selected = true; }
Since your strongly binding to a model property, its the value of the property your binding to which determines which options will be selected and the Selected
property of SelectListItem
is simply ignored. If you want to pre-select options, then set the value of SelectedCategories
in the controller. For example if model.SelectedCategories = new int[] { 1, 3 }
and your options have values 1 to 10, then the 1st and 3rd options will be selected.
Upvotes: 1