Search code examples
asp.net-mvc-3drop-down-menuentity-framework-4.1

Making it easier to populate DropDownLists


In my MVC3 application I have a couple of create forms, and they all have one thing in common, and that is a DropDownList for selecting the language.

Two days ago I learnt that it was not a good idea to send whole entities (or list of them) to the Views. It is better to send properties via ViewModels.

So in my ViewModel, to take care of the DropDownList I have the following:

// Properties for Language DropDownList
[Required(ErrorMessage = "Language is Required")]
public int SelectedLanguageId { get; set; }
public IEnumerable<SelectListItem> Languages { get; set; }

I am still learning Web Development, and I'm not 100% sure that the above is a good idea, I just copied it from this tutorial.

Then what the tutorial author does is something like this:

// GET: Post/Create
public ActionResult Create()
{
    var vm= new NewPostVM();
    var langs = languagesRepository.Languages.ToList();
    vm.Languages = langs.ToSelectListItems(-1);
    if (langs.Count() == 0)
        return RedirectToAction("Index", "Language");
    return View("Create", viewModel);
}

The thing is I do not have a [ ToSelectListItems ] method to call ! so I am guessing he has put in place some sort of Extention method on his Domain (plus I have no idea what the negative one is for).

In any case, how can I populate a repeating (commonly used) DropDownList?


Solution

  • OK so after about an hour in chat with 3nigma, we figured it out. I'll share it with you fellow coders.

    I had a Solution with 2 projects. One holding my Domain and the other my MVC3 application. In the Domain project create a folder called [ Extensions ] (make sure you don't spell it Extentions like I did :D) and add a class naming it something related to the Entity in Question. I named mined [ LanguageEntityExtension ]

    folder structure

    In there a followed this tutorial, and got my code to look like:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web.WebPages.Html;
    using PostssDomain.Entities;
    
    namespace PostsDomain.Extensions
    {
        public static class LanguageEntityExtension
        {
            public static IEnumerable<SelectListItem> ToSelectListItems<T>(this IList<T> langeuageEntities) where T : Language
            {
                 return ToSelectListItems((IEnumerator<Language>)langeuageEntities.GetEnumerator());
            }
    
            public static IEnumerable<SelectListItem> ToSelectListItems(this IEnumerator<Language> langeuageEntities)
            {
                var items = new HashSet<SelectListItem>();
    
                while (langeuageEntities.MoveNext())
                {
                    var item = new SelectListItem();
                    var entity = langeuageEntities.Current;
    
                    item.Value = entity.Id.ToString();
                    item.Text = entity.Name.ToString();
    
                    items.Add(item);
                }
    
                return items;
            }
        }
    }
    

    A couple of things here, make sure you do not forget the words [ static ], and also make sure you are referencing (using statement) the library [ System.Web.WebPages.Html; ] and not [ System.Web.Mvc; ]. You might have to add a Reference to [ System.Web.WebPages.dll ] manually by right-clicking on References folder and adding it that way.

    Now then in my controller, I added the relevant using statement [ using PostsDomain.Extensions; ] and then I was able to do the following:

    var langs = languagesRepository.Languages.ToList();
    vm.Languages = langs.ToSelectListItems();
    

    Where as before having the Extension method I was not. So that is that. Then in the View where you are displaying the DropDownListFor, have it in the following format:

    @Html.DropDownListFor(x => x.SelectedLanguageId, new SelectList(Model.Languages, "value", "text"))
    

    Note the "Value" and "Text".

    That's it. All is working great.

    Thanks once again 3nigma for the help.