Click here to Skip to main content
Licence CPOL
First Posted 29 Nov 2011
Views 59,342
Downloads 1,880
Bookmarked 61 times

MVC3 @Html.CheckBoxList() custom extension

By | 21 Mar 2012 | Article
Extends MVC HtmlHelper class so you can create POSTable checkbox list

If control haven't worked in your MVC3 project, update to latest bugfix v.1.4.2.3!

Install latest stable version via NuGet Package Manager Console!

Install-Package MvcCheckBoxList

Download stable binary version (MvcCheckBoxList.dll) 

Download sample MVC3 project with extension's stable source code

Contents 

Introduction 

One of the cool features of Microsoft MVC web development framework since its inception, was its rich Html helpers library. It provided helpers to create most common html controls like text boxes, drop down lists, text areas, etc. It is done by simply typing Html.<smth> on the MVC view page.

Its all been good and easily customizable, until developers been eventually reaching one blank spot... That spot was a creation of a checkbox lists. There was none, and there is no any control to handle that functionality as of now. Perhaps not until MVC4 will come alive...

To create a checkbox list a developer would have to use a combination of FOR or FOREACH cycle and some html <input> along with it.

While not being a hard thing to do, it could possibly become pretty time consuming. Especially when project was getting bigger and fatter with a whole bunch of repetitive code lying around. And think about adding some advanced functionality and layout. For example, when we want to disable some checkboxes, while at the same time being able to POST it back to your controller, and on top of that, putting it into the <table>, it would become quite bigger than before.

But what if we would want to put it into several columns? It would require even more customization. And would get even bigger. This little extension intends to simplify this task while making it more inline with general MVC workflow.

This plugin is just a simple extension of MVC class 'HtmlHelper', which is used for all Html helpers on MVC views. Since there is no supported CheckBoxList extension built into MVC, this plugin adds it.

Using the code

To use this extension, just download file using the link at the top, and copy it anywhere in your MVC project.

All examples below are shown using MVC3 + Razor view engine. It may also work fine in MVC 1 and 2. But honestly, If you haven't upgraded to MVC3 yet, it's about time you do))

Quick start:

Method 1: Using strongly typed, based on a view model
// Given we have a simple class 'City':
public class City {
  public int Id { get; set; }
  public string Name { get; set; }
}

// And another simple class 'Region' which has many instances of class 'City'
public class Region {
  public IList<City> City { get; set; }
}

// And you defined a similar view model:
public class RegionViewModel {
  public Region Region { get; set; } 
  public IList<City> Cities { get; set; }   
}

// Then on a view which uses 'RegionViewModel' as its @model
// to display a checkbox list of all tests and have some of them selected,
// call in instance of 'CheckBoxList' or 'CheckBoxListFor' extension:

// Option 1 - Manually set name:
@Html.CheckBoxList("Cities",                // NAME of checkbox list (html 'name' property of each
                                            // checkbox in the list)
                   x => x.Cities,           // data source (list of 'Cities' in our case)
                   x => x.Id,               // field from data source to be used for checkbox VALUE
                   x => x.Name,             // field from data source to be used for checkbox TEXT
                   x => x.Region.Cities)    // selected data (list of selected 'Cities' in our case),
                                            // must be of same data type as source data or set to 'NULL'
                       
// Option 2 - Strongly typed name, based on the name of a view model property:
@Html.CheckBoxListFor(x => x.Region,            // each checkbox name will be 'Region'. It can be 
                                                // set to any property in your view model and its name
                                                // will be used as a NAME of each checkbox in the list
                      x => x.Cities,            // ...same as above...
                      x => x.Id,                // ...same as above... 
                      x => x.Name,              // ...same as above...
                      x => x.Region.Cities)     // ...same as above...
    
// And finally, full strongly typed name example:
@Html.CheckBoxListFor(x => x.Cities,            // NAME of checkbox list (html 'name' property of
                                                // each checkbox in the list)
                      x => x.Cities,            // data source (list of 'Tests' in our case)
                      x => x.Id,                // field from data source to be used for checkbox VALUE
                      x => x.Name,              // field from data source to be used for checkbox TEXT
                      x => x.Region.Cities,     // selected data (list of selected 'Tests' in our case),
                      new { htmlAttribute="somevalue" },  // htmlAttribute(s) of each checkbox
                      // creating custom layout of the list (see 'Advanced Usage Examples')
                      new HtmlListInfo(HtmlTag.vertical_columns, 3),
                      new[] {"7", "12", "14"})  // array represents disabled checkboxes
                                                // (values will still POST!)

// In addition, you can use more advanced naming structure:
@Html.CheckBoxListFor(x => x.Region.Cities,     // each checkbox's html 'name' property
                                                // will be 'Quotation.Tests'
                      x => x.Cities,             
                      x => x.Id,                
                      x => x.Name,              
                      x => x.Region.Cities)   

// Added in version 1.4.2.2, you can now send an object containing
// html tag which would be applied to an individual checkbox
// Here, 'Tags' is a variable of type 'object' and equals e.g. 'new {htmlTag = "Value"}'
// (this means you can pass something like 'new {what = "smallCity}', and apply some
// jquery code to it: '$('[what="smallCity"]').css("color", "blue")')
@Html.CheckBoxListFor(x => x.Region.Cities,
                      x => x.Cities,
                      x => x.Id,
                      x => x.Name,
                      x => x.Region.Cities,
                      x => x.Tags)              // tags stored in the data source as an object e.g.:
                                                //'new {htmlTag = "Value"}'
                                                // they will be merged with other tags and applied
                                                // to corresponding checkbox and its label

// Please note: adding custom tags is supported by most 'CheckBoxList' and 'CheckBoxListFor'
// overloads as the very last parameter

If you are not very familiar with this extension, or it all looks confusing, download and run Sample MVC3 Project which contains more uselful examples and scenarios (download link at the top)!

To POST selected values back to the controller, it should accept a string array with the same name as CheckBoxList control name:

// Given we have a simple class 'Test':
public class Test {
  public int Id { get; set; }
  public string Name { get; set; }
}

// And another simple class 'PostedTests'
public class PostedTests {
  // this array will be used to POST values from the form to the controller
  public string[] Tests { get; set; }
}

// And we have a view model 'TestViewModel' that looks like this:
public class TestViewModel {
  public IList<Test> AvailableTests { get; set; }
  public IList<Test> SelectedTests { get; set; }
  public PostedTests PostedTests { get; set; }
}


// And you create checkbox list like that:
@Html.CheckBoxListFor(x => x.PostedTests.Tests,    // each checkbox's html 'name' property will be
                                                   // named 'PostedTests.Tests'
                      x => x.AvailableTests,             
                      x => x.Id,                
                      x => x.Name,              
                      x => x.SelectedTests)

// then to capture list of selected checkboxes in a strongly typed manner, you can accept
// an instance of 'PostedTests' class by controller. Remember, it should be named the same as
// a first part of a checkbox name, in our case it is 'PostedTests'. This will load
// a string list of selected checkbox values into the 'postedTests.Tests' variable
[HttpPost]
public ActionResult Edit(int id, PostedTests postedTests) {
 
  var list_of_selected_tests = postedTests.Tests;

  // do your thing with that array...

  return Edit(id);
}

Method 2: Independent from view model
@{ 
  // given we have some list of names with ids:
  var sourceData = new[] {
                          new {Name = "Monroe", Id = 1},
                          new {Name = "Moscow", Id = 2},
                          new {Name = "New Orleans", Id = 3},
                          new {Name = "Ottawa", Id = 4},
                          new {Name = "Mumbai", Id = 5}
                         };

  // first, we need to convert it to the list of class 'SelectListItems' (part of MVC):
  var dataList = sourceData.Select
    (r => new SelectListItem { Value = r.Id.ToString(), Text = r.Name }).ToList();  

  // OR if we want to have some values selected, first create a string array
  // of selected ids:
  var selectedValues = new[] { "1", "4" };

  // then create list of class 'SelectListItems' with some values selected:
  var dataListSelected = sourceData.Select
    (r => new SelectListItem { Value = r.Id.ToString(), Text = r.Name,
      Selected = selectedValues.Any(s => s == r.Id.ToString())}).ToList();

} 

// finally, just call CheckBoxList extension on your MVC view or partial:
@Html.CheckBoxList("Cities", dataList)

// OR
@Html.CheckBoxList("MoreCities", dataListSelected)

To POST selected values back to the controller, it should accept a string array with the same name as CheckBoxList control name:

[HttpPost]
public ActionResult Edit(int id, string[] Cities) { // or 'MoreCities'
  // do your thing with that array
      
  return Edit(id);
}

Advanced examples (for Model-based approach):

We'll create CheckBoxList which is arranged inside formatted list (given that you have created appropriate view model, using strongly typed way, 'x' represents your model).

Create an instance of checkbox list formatting class 'HtmlListInfo' with parameters: 

@{ var putCheckBoxesIntoUnorderedList = //...select from variants below...
  // arranged inside of the html 'unordered list'
  new HtmlListInfo(HtmlTag.ul); 
  // OR arranged inside of the html 'table' with three columns
  new HtmlListInfo(HtmlTag.table, 3); 
  // OR arranged inside of vertical columns (div's which float left) containing three columns
  new HtmlListInfo(HtmlTag.vertical_columns, 3);
  // OR any of above plus object representing custom html tags (e.g. 'new { htmlTag = "Value" }')
  // html tag will be applied to container holding checkbox list (ul, table, etc.)
  new HtmlListInfo(HtmlTag.SELECT, NUMBER_OF_COLUMNS, new { htmlTag1 = "Value1", htmlTag2 = "Value2" });
}

Apply an instance of 'HtmlListInfo' class to your checkbox list call: 

@Html.CheckBoxList("MyCitiesCheckBoxList",
                   x => x.Cities,
                   x => x.Id, 
                   x => x.Name,
                   x => x.SelectedCities,
                   putCheckBoxesIntoUnorderedList) 

OR use 'CheckBoxListFor' method: 

@Html.CheckBoxListFor(x => x.Cities,  // in that case name of the checkbox list would be 'Cities'
                      x => x.Cities,
                      x => x.Id, 
                      x => x.Name,
                      x => x.SelectedCities,
                      putCheckBoxesIntoUnorderedList) 

Advanced examples (for Model-independent approach):

Note: You can use display customizations below (using HtmlListInfo class and others) for Model-based approach too. 

// Base
@Html.CheckBoxList("Cities", dataList)

// With vertical layout
@Html.CheckBoxList("Cities", dataList, Position.Vertical)

// Arranged inside of an unordered list
@{ var putCheckBoxesIntoUnorderedList = new HtmlListInfo(HtmlTag.ul); }
@Html.CheckBoxList("Cities", dataList, putCheckBoxesIntoUnorderedList)

// Arranged inside 3 columned table with increased font size
@{ var putCheckBoxesIntoTable = new HtmlListInfo(HtmlTag.table, 3); }
@Html.CheckBoxList("Cities", dataList, putCheckBoxesIntoTable)

// Arranged inside 4 vertically sorted floating sections
@{ 
  var putCheckBoxesIntoTable = 
    new HtmlListInfo(HtmlTag.vertical_columns, 4, new { style = "width:100px;" }); 
}
@Html.CheckBoxList("Cities", dataList, putCheckBoxesIntoTable)

// With some values disabled (disabled checkboxes will still POST)
@{ var disabledValues = new[] {"1", "4"}; }
@Html.CheckBoxList("Cities", dataList, null, disabledValues)

// Full control call
@{ var checkBoxHtmlAttributes = new { @class = "checkbox_class" };  }
@Html.CheckBoxList("Cities", dataList, checkBoxHtmlAttributes,
                   putCheckBoxesIntoTable, disabledValues, Position.Vertical)

Possible plans and modifications

  • Add RadioButtonList and DropDownList support, and possibly, other kinds of lists!
  • Create NuGet package for this extension
  • Create MvcCheckBoxList.dll file with extension for easier distribution
  • Add annotations to functions so they will have more details in visual studio autocomplete box
  • Remove dependency on 'SelectListItem' system class (no dependency, if you would use strongly typed approach, however it is still there, if need to use older, view model independent approach)
  • Add advanced sorting options (I decided not to complicate things further, since all kinds of sorting can be easily done like that: YOUR_DATA_LIST.OrderBy(x => x.SOME_VALUE) via LINQ)
  • Cleaning up overload functions (done!)

History

  • v.1.4.2.3
    • Fixed a bug where it requires MVC4 dependency (System.Web.WebPages 2.0.0.0), and doesn't work in MVC3 projects...
  • v.1.4.2.2
    • NuGet package added!
    • Additional parameter for both 'CheckBoxList' and 'CheckBoxListFor' - 'htmlAttributesExpr' allows to pass custom html tags from database to be applied to each individual checkbox (see good exaple of this in sample MVC3 project)
    • Improved name generation
    • Numerous other small fixes...
  • v.1.3c
    • Some minor bug fixes done
    • Created a sample MVC3 .NET 4.0 site which comes along with this control, so you can test it first hand!
  • v.1.3b
    • Added function annotations, some code cleanup
  • v.1.3a
    • Instead of plain checkbox name it now creates a label linked to checkbox, so you can also click on the label to select that checkbox!

      Many thanks to william0565 for idea !
  • v.1.3
    • 'CheckBoxListFor' now generates full name from a lambda expression: e.g.: @Html.CheckBoxListFor(model => model.SomeClass.SubClass .... ) will create a list of checkboxes with 'name="SomeClass.SubClass"', where older version would create only 'name="SubClass"'
  • v.1.2
    • You can now create strongly typed checkbox list from your view model!
    • Added new method 'CheckBoxListFor' to be used with strongly typed approach
  • v.1.1
    • Added new option 'HtmlTag.vertical_columns', which allows checkboxes to be arranged inside 4 vertically sorted floating sections
    • Overload functions cleanup
    • Overall code cleanup
  • v.1.0
    • Initial release!

Regards

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mikhail Tsennykh

Web Developer
Nûby, Inc.
United States United States

Member

Namaste from Monroe, Louisiana!

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionHow to show the pop up when no items are selected in checkboxlist PinmemberMurthy Narasimha4:45 9 May '12  
AnswerRe: How to show the pop up when no items are selected in checkboxlist PinmemberMikhail Tsennykh (devnoob)7:25 9 May '12  
GeneralRe: How to show the pop up when no items are selected in checkboxlist PinmemberMurthy Narasimha7:50 9 May '12  
AnswerRe: How to show the pop up when no items are selected in checkboxlist PinmemberMikhail Tsennykh (devnoob)8:03 9 May '12  
GeneralRe: How to show the pop up when no items are selected in checkboxlist PinmemberMurthy Narasimha8:22 9 May '12  
AnswerRe: How to show the pop up when no items are selected in checkboxlist PinmemberMikhail Tsennykh (devnoob)8:52 9 May '12  
QuestionClient side PinmemberWitchfinder0:24 22 Feb '12  
AnswerRe: Client side PinmemberMikhail Tsennykh (devnoob)3:28 22 Feb '12  
QuestionAny way to not have so much code in the controller? Pinmemberremesqny5:55 17 Feb '12  
AnswerRe: Any way to not have so much code in the controller? PinmemberMikhail T. (devnoob)6:31 17 Feb '12  
GeneralRe: Any way to not have so much code in the controller? [modified] Pinmemberremesqny6:49 17 Feb '12  
AnswerRe: Any way to not have so much code in the controller? [modified] PinmemberMikhail T. (devnoob)9:01 17 Feb '12  
GeneralRe: Any way to not have so much code in the controller? Pinmemberremesqny9:29 17 Feb '12  
AnswerRe: Any way to not have so much code in the controller? PinmemberMikhail T. (devnoob)10:31 17 Feb '12  
BugRe: Any way to not have so much code in the controller? PinmemberMikhail T. (devnoob)6:36 17 Feb '12  
GeneralRe: Any way to not have so much code in the controller? Pinmemberremesqny7:07 17 Feb '12  
QuestionFormatting... PinmvpDave Kreskowiak16:02 15 Feb '12  
AnswerRe: Formatting... PinmemberMikhail T. (devnoob)3:21 16 Feb '12  
QuestionMessage Automatically Removed Pingroupghjtyktyk15:52 15 Feb '12  
QuestionMessage Automatically Removed Pingroupghjtyktyk15:50 15 Feb '12  
QuestionUpdates to name and html attribute generation PinmemberJoshua Russo7:45 10 Feb '12  
SuggestionRe: Updates to name and html attribute generation PinmemberMikhail T. (devnoob)10:21 10 Feb '12  
GeneralRe: Updates to name and html attribute generation PinmemberJoshua Russo12:34 12 Feb '12  
NewsRe: Updates to name and html attribute generation PinmemberMikhail T. (devnoob)5:23 13 Feb '12  
GeneralRe: Updates to name and html attribute generation PinmemberJoshua Russo10:26 13 Feb '12  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120528.1 | Last Updated 21 Mar 2012
Article Copyright 2011 by Mikhail Tsennykh
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid