Having returned to this problem after a few months I\'ve added my current best answer below.
In the original question I was still looking for a simple way to achieve a g
There is a way to create a generic DropDown which I've mangled together from a few pointers on StackOverflow and this article on CodeProject. Comments on whether this follows best practice would be appreciated.
I use both an AddList and an EditList to allow for a selected item on the EditList and some jQuery based on html class attributes. The generic EditList is created as follows:
I have a viewmodel for any DropDown that fits with the generic pattern and then a ViewModel for the entity I'm returning. Annotations are held in a validation file.
public class DropDownViewModel
{
public IEnumerable<SelectListItem> Items { get; set; }
}
public partial class OrganisationEditViewModel
{
public int entityID { get; set; }
public string entityName { get; set; }
public DropDownViewModel entityTypeID { get; set; }
public string notes { get; set; }
}
[MetadataTypeAttribute(typeof(OrganisationEditViewModelMetaData))]
public partial class OrganisationEditViewModel
{
}
public class OrganisationEditViewModelMetaData
{
[Key]
[ScaffoldColumn(false)]
[HiddenInput(DisplayValue = false)]
public int entityID { get; set; }
[Required]
[Display(Name = "Organisation")]
public string entityName { get; set; }
[Required]
[Display(Name = "Entity Type")]
[UIHint("_dropDownEdit")]
public DropDownViewModel entityTypeID { get; set; }
[Display(Name = "Notes")]
public string notes { get; set; }
}
The UIHint annotation on the ViewModel points to an Editor Template. I'm using chosen.js on my lookups, hence the html attributes.
@model WhatWorks.ViewModels.DropDownViewModel
@Html.DropDownList("", Model.Items, new { @class = "chosen chosenLookup" })
The controller queries the current entity to get the selected string for the EditList. The DropDown is called from the GetEditList<O>
function in the repository. The ViewModel is then mapped via Automapper (GetUpdate(id)
).
public ActionResult Edit(int id = 0)
{
var query = _repo.GetByID(id);
string selected = query.tEntityType.entityTypeID.ToString();
DropDownViewModel entityType = new DropDownViewModel
{
Items = _repo.GetEditList<tEntityType>("entityType", "entityTypeID", selected)
};
OrganisationEditViewModel a = GetUpdate(id);
a.entityTypeID = entityType;
if (a == null)
{
return HttpNotFound();
}
return View(a);
}
The generic DropDown repository method gets an IEnumerable
set of data from the calling type <O>
(tEntityType
in this case). The return
method converts everything into strings and checks for the selected item.
//generic Edit dropdown
public IEnumerable<SelectListItem> GetEditList<O>(string text, string value, string selected)
where O : class
{
IEnumerable<O> result = context.Set<O>();
var query = from e in result
select new
{
Value = e.GetType().GetProperty(value).GetValue(e, null),
Text = e.GetType().GetProperty(text).GetValue(e, null)
};
return query.AsEnumerable()
.Select(s => new SelectListItem
{
Value = s.Value.ToString(),
Text = s.Text.ToString(),
Selected = (selected == s.Value.ToString() ? true : false)
});
}
Finally, the view renders the DropDown via a standard Html.Editor
which picks up the Editor Template from the UIHint
annotation on the validation file.