ASP.Net MVC: Multiple Checkboxes and Strongly Typed Views

This might be a first, but I actually stole this from myself off Stackoverflow. Posted it and thought it might be useful to share with the 1 live person who reads this blog and the 90 other bots… And I’m not sure about the 1 live person.

So here’s the situation, it’s late, you’ve got a strongly typed view that has a checkbox list, and you are desperate for an answer on how to handle it…. and now you’re scraping the bottom of the barrel. Well, good news is, I have the answer.

Let’s say you have a Book class that has a list of Categories. The Category class is simple, just has an id and name.

  public class Book
  {
    public Int32 BookId { get; set; }
    public IList<Category> Categories { get; set; }
  }

  public class Category
  {
    public Int32 Id { get; set; }
    public String Name { get; set; }
  }

Now you could try and figure out a way to create a typed view using the Book class. You could also stomp on your left foot until it bleeds. Who am I to judge you for liking pain? (Sick f—) For those who don’t want to go through that nightmare, I have an alternative: Create two new classes, one to set the view and one to handle the post back.

public class ViewBookModel
{
  public ViewBookModel(Book book, IList<Categories> categoryList)
  {
    BookId = book.Id;
    CategoryList = categoryList;
  }

  public Int32 BookId { get; private set; }
  IList<Categories> CategoryList { get; set; }
}

First the class to set the view. As you can see, there is a book id that corresponds to a book object’s id (DUH) and the category list which you will set in the original action.

  [AcceptVerbs(HttpVerbs.Get)]
  public ActionResult EditBook(Int32 bookId)
  {
     Book foundBook = Book.GetById(bookId);
     IList<Category> categoryList = Category.GetAll();
     ViewBookModel model = new ViewBookModel(foundBook, categoryList);
     return View(model);
  }

And then your markup for the checkbox list will be something like this:

  <%
    foreach(var category in Model.CategoryList)
    {
  %>
      <input type="checkbox" name="CategoryIds" value="<%= category.Id %>" />
  <%
    }
  %>

Notice that the name for every input is CategoryIds. This is because this will be the name of the collection of ids on the model for posting:

  public class ViewBookInModel
  {
    public String BookId { get; set; }
    public Int32[] CategoryIds { get; set; }
  }

And the action method would look like:

  [AcceptVerbs(HttpVerbs.Post)]
  public ActionResult UpdateBook(ViewBookInModel book)
  {
    foreach(Int32 id in book.CategoryIds)
    {
      ...
    }
  }

And boom, problem solved. You can now use a strongly typed View with a checkbox list. Go forth and be fruitful.