ASP.NET MVC 3 List<T> to IEnumerable<SelectListItem>

18,057

Solution 1

You could provide callbacks that obtain the key and the value and then use those. Apart from that you can create it as an extension method:

Extension method:

public static List<SelectListItem> ToSelectList<T>(this List<T> Items, Func<T, string> getKey, Func<T, string> getValue, string selectedValue, string noSelection, bool search = false)
    {
        List<SelectListItem> items = new List<SelectListItem>();

        if (search)
        {
            items.Add(new SelectListItem { Selected = true, Value = "-1", Text = string.Format("-- {0} --", noSelection) });
        }

        foreach (var item in Items)
        {
            items.Add(new SelectListItem
            {
                Text = getKey(item),
                Value = getValue(item),
                Selected = selectedValue == getValue(item) ? true : false
            });
        }

        return items
            .OrderBy(l => l.Text)
            .ToList();
    }

Usage:

List<Org>() parentOrganisations = // fetch here
model.Organisations = parentOrganisations.ToSelectList(org => org.ID.ToString(), 
                                                       org => org.OrganisationName,
                                                       "-1", 
                                                       "-- None -- ", 
                                                       true);

Note: I typed this in the SO-editor, so you might have some syntax errors (they should be easy to solve though).

Solution 2

You can do in controller only like this: -

List<SelectListItem> dropdownItems = parentOrganisations
    .Select(item => new SelectListItem
    {
        Value = item.ID.ToString(),
        Text = item.OrganisationName,
        Selected = "-1" == item.ID.ToString() ? true : false
    })
    .ToList();
Share:
18,057
Paul
Author by

Paul

A software consultant focusing on all things Microsoft, specifically ASP.NET MVC, SQL Server, Business Intelligence and sometimes dabbling into the murky world of SharePoint. Based in sunny Brisbane, Queensland I'm also a keen (if not pretty awful) golfer and can be found playing anywhere that offers me a good deal.

Updated on June 09, 2022

Comments

  • Paul
    Paul almost 2 years

    I'm not currently happy with the way that my DropDownListFor() objects are populated. I'm attempting to find as generic way of populating IEnumerable as possible. This is what I have so far.

    Helper:

    public static List<SelectListItem> ToSelectList(IDictionary<string,string> dictionaryItems, string selectedValue, string noSelection, bool search = false)
        {
            List<SelectListItem> items = new List<SelectListItem>();
    
            if (search)
            {
                items.Add(new SelectListItem { Selected = true, Value = "-1", Text = string.Format("-- {0} --", noSelection) });
            }
    
            foreach (var item in dictionaryItems)
            {
                items.Add(new SelectListItem
                {
                    Text = item.Key,
                    Value = item.Value,
                    Selected = selectedValue == item.Value ? true : false
                });
            }
    
            return items
                .OrderBy(l => l.Text)
                .ToList();
        }
    

    Controller:

    [HttpGet]
        public ActionResult Index()
        {
            var model = new CreateModel();
    
            var parentOrganisations = _orgs.FindBy(o => o.OwningOrganisationID == Globals.OrganisationID || o.ID == Globals.OrganisationID)
                .OrderBy(o => o.OrganisationName);
    
            Dictionary<string, string> items = new Dictionary<string, string>();
    
            foreach (var item in parentOrganisations)
            {
                items.Add(item.OrganisationName, item.ID.ToString());
            }
    
            model.Organisations = SelectLists.ToSelectList(items, "-1", "-- None -- ", true);
    
            return View(model);
        }
    

    View:

    <div class="control-group">
            <label class="control-label">Parent Organisation</label>
            <div class="controls">
                @Html.DropDownListFor(m => m.ParentOrganisationID, Model.Organisations, new { @class = "input-xlarge"})
                <p class="help-block">Select a parent organisation to create a branch</p>
            </div>
        </div>
    

    There seems to be A LOT of repetitive code in the controller. It takes a generic list, add's the Value and Text to a Dictionary and then uses that as input for a helper which builds up the select list to send as part of the model.

    Does anyone have any better ways to achieve this? I hate having bloat in my controller, and when I get several drop downs on a form this is exactly what will happen in this instance.

    Thanks,

    EDIT - Thanks to Kenneth's helper method, I've now consolidated the whole thing into one call in the controller:

                model.Organisations = _orgs.FindBy(o => o.OwningOrganisationID == Globals.OrganisationID || o.ID == Globals.OrganisationID)
                .OrderBy(o => o.OrganisationName)
                .ToList()
                .ToSelectList(org => org.OrganisationName, org => org.ID.ToString(), "-1", "None", true);