hyperN
hyperN

Reputation: 2754

mvc 4 MultiSelect list & EF many to many

I have these entities (there is many to many connection between them):

public class Post
{     
    public Guid PostId { get; set; }     
    public string Name { get; set; }       
    public virtual ICollection<Tag> Tags { get; set; }
}

  public class Tag
{
    public int TagId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Post> Posts { get; set; }
}

I'd like user, when he creates Post, to choose data from MultiSelectList and MultiSelectList to pass that data to Post.Tags. How can I do that ?

Upvotes: 5

Views: 9103

Answers (1)

Patrick Magee
Patrick Magee

Reputation: 2989

I have something similar, a Product belongs to many Categories and a Category, has many products.

In my administrative view for creating new products, I am able to allow the user to select mutliple "tags" of categories that this product should be listed under.

Because of so many categories I tend to avoid multi select lists and use a sort of auto suggest with ajax to retrieve categories and populate them using a jQuery plugin such as TagIt.

But for simplicity you can use this in your Controller

public class HomeController : Controller
{
    public ActionResult Create()
    {
        var tags = new List<Tag>()
            {
                new Tag() { TagId = 1, Name = "Planes", Posts = new Collection<Post>() },
                new Tag() { TagId = 2, Name = "Cars", Posts = new Collection<Post>() },
                new Tag() { TagId = 2, Name = "Boats", Posts = new Collection<Post>() }
            };

        ViewBag.MultiSelectTags = new MultiSelectList(tags, "TagId", "Name");

        return View();
    }

    [HttpPost]
    public ActionResult Create(Post post, int[] tags) // Tags is not case-sensative from model binder when html element name="tags" <-- array passed back to controller
    {

        // Find Tag from Database
        // Attach tag entity to Post

        // foreach(var tagId in tags)
        //    var tag = context.Tags.find(tagId)
        //    post.Tags.Add(tag);

        // context.SaveChanges();

        return RedirectToAction("Create");
    }

}

And inside your View/Create.cshtml

@model MvcApplication1.Models.Post

<h2>Create</h2>


@using (Html.BeginForm("Create", "Home", FormMethod.Post))
{
    <label>Name</label>
    @Html.TextBoxFor(model => model.Name)

    <label>Tags For Post</label>
    @Html.ListBox("Tags", (MultiSelectList)ViewBag.MultiSelectTags)

    <input type="submit" value="Submit Post"/>
}

all Selected tags:

Then when multiple are selected on posting back to controller you can see in debug that the model binder knows to send array back from html element name "tags"

Upvotes: 13

Related Questions