Geeks With Blogs
Pounding Code technological rantings and code samples

I had been kicking around the idea of writing an article discussing the various approaches in MVC to populating the ubiqutous dropdown list box, when at lucnch today, I read that the prolific K. Scott Allen had beat me to it. Rather than rehash what he wrote, I'm not free to skip the part discussing the basics of adding a SelectList to a ViewModel and discuss the various other approaches.

What's the ViewModel?

That is a class representing a DTO of your entity that is more readily consumed by a view. It may contain validation, UI hints as well as an Enumberable for our SelectList.

While this works quite well, there are a few downsides with this approach, the largest being that you need to re-hydrate the list if, when you post back to the server an error occurs. K. Scott Allen mention how some folks might deal with this by having an inbound & outbound view. To my thnking this is a HUGE violation of DRY and is undesirable.

Another approach is to re-hydrate the dropdown when ever you error trap and need to resend the view to the server:

catch(Exception)
{
model.Albums = _repository.FindAllAlbums().ToSelectItems(selectedId);
}

There's nothing really wrong with this, so long as you remember to do it on all of your errors & validation failures.

What I've opted to do most recently, was to create a helper class for all of my work horse dropdowns. I've removed most of the methods from my actual class so this example isn't muddled, but you should be able to see how it works fairly easily.

The helper has an enum set to the type of list the view is interested in. The Get method uses a switch to return a call to the list of the type desired. Additional properties manage filtering, if required and adjusting the selected index. The GetAll methods used by the ObjectFactory pull on my Service Layer where the values are cached, so overall, the performance is quite good.


  public class SelectListHelper
    {      
        private object _htmlAttributes = null;
        private Category[] _categories = null;     
        private Response[] _response = null;
        private SelectList _selectList = null;
        private string _label = null;
        private bool _showLabel = true;

        public enum ListOfType{
            Category,
            Response
        }
        public enum  FilterOfType
        {          
            Category,          
            Response
        }
       
        public object FilterId { get; set; }
        public Enum FilterResults { get; set; }
        public SelectList SelectList {
            get {
                switch (ReturnsListOf)
                {
                    case ListOfType.Category:
                        return GetCategoriesSelectList();                   
                    case ListOfType.Response:
                        return GetResponseSelectList();
                    default:
                        return _selectList;
                }
            }
            set {_selectList = value; }
        }

        public bool ShowLabel
        {
            get { return _showLabel; }
            set { _showLabel = value; }        
        }

        private string GetLabelName()
        {
          
                switch (ReturnsListOf)
                {
                    case ListOfType.Category:
                        return  "Domain";                  
                    case ListOfType.Response:
                        return "Response";
                    default:
                        return string.Empty;
                }
           }
        private Category[] Categories
        {
            get
            {
                if (_categories == null)
                {
                    _categories = ObjectFactory.GetInstance().GetAll().ToArray();
}
return _categories;
}
set { _categories = value; }
}

private Response[] Response
{
get
{
if (_response == null)
_response = ObjectFactory.GetInstance().GetAll().ToArray();
return _response;
}
set { _response = value; }
}

private SelectList GetCategoriesSelectList()
{
return new SelectList(Categories, "Id", "Key", SelectedValue);
}
private SelectList GetResponseSelectList()
{
return new SelectList(Response, "Id", "Key", SelectedValue);
}

public object SelectedValue { get; set; }

public object HtmlAttributes
{
get
{
if (IsPostBack)
{
_htmlAttributes = new { onchange = "this.form.submit()" };
}
return _htmlAttributes;
}
set { _htmlAttributes = value; }
} /// /// Flag for which default collection will hydrate the SelectList /// public ListOfType ReturnsListOf { get; set; } /// /// If set to true, all other html attributes are overwritten /// public bool IsPostBack { get; set; } public string Label { get { return string.IsNullOrEmpty(_label) ? GetLabelName() : _label; } set { _label = value; } } /// /// Readonly name used by the dropdown the ReturnsListOfValue + Id /// public string Name { get { return ReturnsListOf + "Id"; } }

The Shared View is pretty straight forward: It renders the dropdown with an optional label & form, in case I wish the dropdown to post back to the controller.

 


<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>    
<%if (Model.ShowLabel)
{ %>
<%= Html.Label(Model.Label) %>
<%} %> <%if (Model.IsPostBack) { using (Html.BeginForm()) { %> <%= Html.DropDownList(Model.Name, (SelectList)Model.SelectList, "(Select)", Model.HtmlAttributes) %> <% } } else { %> <%= Html.DropDownList(Model.Name, (SelectList)Model.SelectList, "(Select)", Model.HtmlAttributes)%> <% } %>

What is in the View is even easier to digest


Html.RenderPartial(MVC.Shared.Views._SelectList, new SelectListHelper { ReturnsListOf = SelectListHelper.ListOfType.EvaluationType, SelectedValue = ViewData["EvaluationTypeId"] , IsPostBack=true});

Posted on Thursday, February 4, 2010 10:26 PM MVC | Back to top


Comments on this post: Dropdown list ReDux

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © James Fleming | Powered by: GeeksWithBlogs.net