BForms exposes two ways of building single or multi-select elements using Razor HTML extensions. One way is through the BsControlAttribute in combination with BsSelectFor helper. If you choose to do so, the BsSelectFor will render the specified select input type based on the selected value of the BsControlType enum. Another way is to use the specialized helpers like BsDropDownListFor, BsListBoxFor and so on.

The BsSelectList<T> class

The BsSelectList<T> class was created in order to extend SelectList's functionalities. The generic parameter T represents the type of the value selected by the user. Unlike its framework-provided counterpart, you now have a type-safe way of working with list-like inputs.

Extension methods

  • FromSelectList - creates a new BsSelectList<T> from an existing IEnumerable<SelectListItem>
  • FromEnum - creates a new BsSelectList<T> from an enum. The text property of the newly created list items will be filled with the data contained in the Display attribute of each enum value. If there is no such attribute, the enum value's name will be used.

BsSelectListItem

BsSelectListItem is derived from SelectListItem. It implements the following additional properties:

  • Dictionary<string, string> Data - Using the Data property you can provide the option with additional data. The data found in this dictionary will be rendered as following in the resulted html:
    <option [data-key1="value1", ...]></option>
  • string GroupName - This, along with the GroupKey property, removes the need of defining a separate type for grouped lists.
  • string GroupKey - - This, along with the GroupName property, removes the need of defining a separate type for grouped lists.

Select helper

Select Extensions

public static MvcHtmlString BsSelectFor<TModel, TKey>(
	this HtmlHelper<TModel> htmlHelper,
	Expression<Func<TModel, BsSelectList<TKey>>> expression)
	
public static MvcHtmlString BsSelectFor<TModel, TKey>(
	this HtmlHelper<TModel> htmlHelper,
	Expression<Func<TModel, BsSelectList<TKey>>> expression, 
	object htmlAttributes)
	
public static MvcHtmlString BsSelectFor<TModel, TKey>(
	this HtmlHelper<TModel> htmlHelper,
	Expression<Func<TModel, BsSelectList<TKey>>> expression, 
	object htmlAttributes, 
	object dataOptions)
		
public static MvcHtmlString BsSelectFor<TModel, TKey>(
	this HtmlHelper<TModel> htmlHelper,
	Expression<Func<TModel, BsSelectList<TKey>>> expression, 
	IDictionary<string, object> htmlAttributes,
	IDictionary<string, object> dataOptions)

		

DropDownList

In order to render a single-select input of type dropdown list you will need to use the @Html.BsSelectFor helper extension and decorate your model property with [BsControl(BsControlType.DropDownList)].

Example

Model

public class RegisterModel
{
    [Display(Name = "Location", Prompt = "Choose your country")]
    [BsControl(BsControlType.DropDownList)]
    public BsSelectList<int?> CountryList { get; set; }
    
    ...
}

View

<div class="form-group">
    @Html.BsLabelFor(m => m.CountryList)
    <div class="input-group">
        @Html.BsSelectFor(m => m.CountryList)
        @Html.BsValidationFor(m => m.CountryList)
    </div>
</div>

You can also use it by loading remote data. Just decorate it with [BsControl(BsControlType.DropDownListRemote)].

Example

View

<div class="form-group">
    @Html.BsLabelFor(m => m.CountryList)
    <div class="input-group">
      @Html.BsSelectFor(m => m.CountryList, null, new
      {
          formatResult = "<img class='flag' src='" + Url.Content("~/Content/Images/Flags/") + "{{id}}.png'/> <span class='flag-text'>{{text}}</span>",
          url = Url.Action("GetCountriesPaged", "Login", new { area = "Demo" })
      })
      @Html.BsValidationFor(m => m.CountryList)
    </div>
</div>

Controller (remote data action)

public BsJsonResult GetCountriesPaged(int page, string search)
{
    var pageSize = 10;
    var ddlWithSelected = Lists.AllCounties<string>();

    var q = ddlWithSelected.Items
        .Where(x => x.Text.ToLower().Contains(search.ToLower()));

    var items = q.Skip((page - 1) * pageSize)
        .Take(pageSize)
        .ToList();

    return new BsJsonResult(new
    {
        PageSize = pageSize,
        Count = q.Count(),
        Items = items
    });
}

ListBox

In order to render a multi-select input of type listbox list you will need to use the @Html.BsSelectFor helper extension and decorate your model property with [BsControl(BsControlType.ListBox)].

Example

Model

public class RegisterModel
{
    [Display(Name = "Technologies", Prompt = "Choose your favorite technologies")]
    [BsControl(BsControlType.ListBox)]
    public BsSelectList<List<int>> TechnologiesList { get; set; }
    
    ...
}

View

  <div class="form-group">
    @Html.BsLabelFor(m => m.TechnologiesList)
    <div class="input-group">
      @Html.BsSelectFor(m => m.TechnologiesList)
      @Html.BsValidationFor(m => m.TechnologiesList)
    </div>
  </div>

You can also use it by loading remote data same way as the BsControlType.DropDownListRemote input, just decorate it with [BsControl(BsControlType.ListBoxRemote)].

TagList

In order to render a multi-select input with add in-place you will need to use the @Html.BsSelectFor helper extension and decorate your model property with [BsControl(BsControlType.TagList)].

The difference between TagList Input and ListBox Input is that TagList Input lets you insert inputs that are not in the dropdown list that appears when you type, while ListBox only let's them select an option from the ones displayed in the dropdown and does not allow for new inputs.

Example

Model

public class RegisterModel
{
    [Display(Name = "Programming languages", Prompt = "Type your favorite programming languages")]
    [BsControl(BsControlType.TagList)]
    public BsSelectList<List<string>> LanguagesList { get; set; }
    
    ...
}

View

  <div class="form-group">
    @Html.BsLabelFor(m => m.LanguagesList)
    <div class="input-group">
      @Html.BsSelectFor(m => m.LanguagesList)
      @Html.BsValidationFor(m => m.LanguagesList)
    </div>
  </div>

CheckboxList

In order to render a multi-select input of type checkbox list you will need to use the @Html.BsSelectFor helper extension and decorate your model property with [BsControl(BsControlType.CheckboxList)].

Example

Model

public class RegisterModel
{
    [Display(Name = "What ASP.NET flavors do you use")]
    [BsControl(BsControlType.CheckBoxList)]
    public BsSelectList<List<int>> TechnologyList { get; set; }   
    
    ...
}

View

  <div class="form-group">
    @Html.BsLabelFor(m => m.TechnologyList)
    <div class="input-group">
      @Html.BsSelectFor(m => m.TechnologyList)
      @Html.BsValidationFor(m => m.TechnologyList)
    </div>
  </div>

RadioButtonList

In order to render a single-select input of type radio button list you will need to use the @Html.BsSelectFor helper extension and decorate your model property with [BsControl(BsControlType.RadioButtonList)].

Example

Model

public class RegisterModel
{
    [Required]
    [Display(Name = "Receive email notifications", Description = "Your register...")]
    [BsControl(BsControlType.RadioButtonList)]
    public BsSelectList<NotificationType?> NotificationList { get; set; }
    
    ...
}

Data binding

//create a BsSelectList from an enum
var notificationList = BsSelectList<NotificationType?>.FromEnum(typeof(NotificationType));
notificationList.SelectedValues = NotificationType.Daily;

registerModel.NotificationList = notificationList;

...

public enum NotificationType
{
    [Display(Name = "Never")]
    Never = 1,
    [Display(Name = "Daily")]
    Daily = 2,
    [Display(Name = "Weekly")]
    Weekly = 3,
    [Display(Name = "Monthly")]
    Monthly = 4
}

View

  <div class="form-group">
    @Html.BsLabelFor(m => m.NotificationList)
    <div class="input-group">
      @Html.BsSelectFor(m => m.NotificationList)
      @Html.BsValidationFor(m => m.NotificationList)
    </div>
  </div>

Autocomplete

In order to render an autocomplete textbox you will need to use the @Html.BsSelectFor helper extension and decorate your model property with [BsControl(BsControlType.Autocomplete)]. This component uses Twitter Typeahead jQuery plugin.

Example

Model

public class RegisterModel
{
    [Required]
    [Display(Name = "Programming IDE", Prompt = "Type your favorite IDE")]
    [BsControl(BsControlType.Autocomplete)]
    public BsSelectList<string> IdeList { get; set; } 
    
    ...
}

View

  <div class="form-group">
    @Html.BsLabelFor(m => m.IdeList)
    <div class="input-group">
      @Html.BsSelectFor(m => m.IdeList)
      @Html.BsValidationFor(m => m.IdeList)
    </div>
  </div>