How can I get my MultiSelectList to bind to my data model?

asp.net-mvc asp.net-mvc-5 c# entity-framework entity-framework-6

Question

I have a many to many relationship between cars and many other tables. In my view I want to be able to have a multiselect list for items such as lights. I've tried many different formats I can't seem to get the list to set selected items.My preferred way to do it would be @Html.ListBoxFor(model => model.enitity.relatedentity, Model.SomeSelectListItemList) , but I can not seem to get list to set selected items in the view.

Below is my code I was testing with I use Asp.net MVC5, C# and entity framework 6.

This is my controller action

    // GET: Car/Edit/
    [Authorize(Roles = "Ecar")]
    public ActionResult Edit(int id)
    {


        CarsEditViewModel carEditViewModel = new CarsEditViewModel();

        carEditViewModel.Cars = unitOfWorkcar.CarRepository.FindIncluding(id);

        IList<Approval> approvalList = unitOfWorkcar.ApprovalRepository.All.ToList();
        IList<Connector> connectorList = unitOfWorkcar.ConnectorRepository.All.ToList();
        IList<InputVoltage> inputVoltagesList = unitOfWorkcar.InputVoltageRepository.All.ToList();



        carEditViewModel.ApprovalList = from c in approvalList select new SelectListItem { Text = c.Name, Value = c.Id.ToString(), Selected = true};

        carEditViewModel.Categories = new MultiSelectList(carEditViewModel.ApprovalList, "Value", "Text", "Selected");


       // ,carEditViewModel.ApprovalList.Select(c => c.Text),carEditViewModel.ApprovalList.Select(c => c.Selected)

        //carEditViewModel.ApprovalList = from c in approvalList select new MultiSelectList( //{ Selected = (carEditViewModel.Cars.Approvals.Any(app => app.Id == c.Id)) , Text = c.Name, Value = c.Id.ToString() };
       // carEditViewModel.ConnectorList = from c in connectorList select new SelectListItem { Selected = true,  Text = c.Name, Value = c.Id.ToString() };
        carEditViewModel.InputVoltageList = from c in inputVoltagesList select new SelectListItem { Text = c.Name, Value = c.Id.ToString() };



        return View(carEditViewModel);

    }

Here is my view

@model NewBobPortal.ViewModels.CarsEditViewModel

 @using (Html.BeginForm())
{



   @* @Html.ListBoxFor("SelectedApprovals",model => model., new { @class = "multiselect" })*@
    @*@Html.ListBoxFor(model => model.Cars.Approvals, Model.ApprovalList)
    @Html.ListBoxFor(model => model.Cars.Connectors,Model.ConnectorList, new {Multiple = "multiple"})
    @Html.ListBoxFor(model => model.ConnectorList, Model.ConnectorList)*@
    @*@Html.ListBox("test",Model.Cars.InputVoltages, Model.InputVoltageList)*@
    @Html.DropDownList("somethingelse", new MultiSelectList(Model.InputVoltageList, "Value", "Text", Model.InputVoltageList.Select(c => c.Value)), new { multiple = "multiple" })
    @Html.DropDownListFor(model => model.Cars.InputVoltages , new MultiSelectList(Model.LensColorList, "Value", "Text", Model.LensColorList.Select(c => c.Value)), new { multiple = "multiple" })


    @Html.ListBoxFor(m => m.Cars.Approvals, Model.Categories)



    <p>
        <input type="submit" value="Save" />
    </p>

}

This is my viewmodel

using NewBobPortal.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

 namespace NewBobPortal.ViewModels
 {
public class CarsEditViewModel
{
    public Car Cars { get; set; }
    public IEnumerable<SelectListItem> ApprovalList { get; set; }
    public IEnumerable<MultiSelectList> ConnectorList { get; set; }
    public IEnumerable<SelectListItem> InputVoltageList { get; set; }




    public MultiSelectList Categories { get; set; }
    public IEnumerable<Approval> SelectedCategories { get; set; }

}

}

Popular Answer

The biggest problem with posting values for a many-to-many relationship is that there's no direct field to bind to on your model. This is where view models become very handy, which you're already using, but not quite in the right way for this.

First you need your SelectList, which can actually just be an IEnumerable<SelectListItem>. This will contain all available options, which is easy enough. So in your view model:

public IEnumerable<SelectListItem> CategoryChoices { get; set; }

And in your action:

carEditViewModel.CategoryChoices = approvalList.Select(m => new SelectListItem {
    Text = c.Name,
    Value = c.Id.ToString()
});

Notice that I'm not setting Selected: we'll let the HtmlHelper handle that. I'm also not dealing with a MultiSelectList yet either.

Now, you'll also need something to post back to, since your values will be ids, we'll use a List<int>, so in your view model:

private List<int> selectedCategories;
public List<int> SelectedCategories
{
    get
    {
        if (selectCategories == null)
        {
            selectedCategories = Categories.Select(m => m.Id).ToList();
        }
        return selectedCategories;
    }
    set { selectedCategories = value; }
}

There's a bit going on here. The set method of the property is simple: when we get a posted value back, just set selectedCategories to that. The get is a bit more complicated: here we need to condense down your list of category objects (called Categories here because I don't know where this is actually coming from) into a simple list of ids for those categories.

Now, in your view:

@Html.ListBoxFor(m => m.SelectedCategories, Model.CategoryChoices)

That's all you need. You're using a ListBox control so it's already a multiple select list. And, by binding it to the list of all currently selected ids, it knows which items to select automatically in the list of SelectListItems it gets from Model.CategoryChoices.

In your post action, you then need to translate these ids into their associated objects:

 var newCategories = repository.Categories.Where(m => carEditViewModel.SelectedCategories.Contains(m.Id));

Then, you can set your model's categories to this new list manually:

car.Categories = newCategories;



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why