Creating a dropdownlist from your controller or view model - asp.net-mvc

How would I create a SelectList in my controller and pass it to my view? I need to give the "-- Select --" option a value of 0.
I'm responding to the replies that I got from Jeremey of Fluent Validation.
This is what I currently have. My view model:
[Validator(typeof(CreateCategoryViewModelValidator))]
public class CreateCategoryViewModel
{
public CreateCategoryViewModel()
{
IsActive = true;
}
public string Name { get; set; }
public string Description { get; set; }
public string MetaKeywords { get; set; }
public string MetaDescription { get; set; }
public bool IsActive { get; set; }
public IList<Category> ParentCategories { get; set; }
public int ParentCategoryId { get; set; }
}
My controller.
public ActionResult Create()
{
List<Category> parentCategoriesList = categoryService.GetParentCategories();
CreateCategoryViewModel createCategoryViewModel = new CreateCategoryViewModel
{
ParentCategories = parentCategoriesList
};
return View(createCategoryViewModel);
}
This is what I have in my view:
#Html.DropDownListFor(x => x.ParentCategoryId, new SelectList(Model.ParentCategories, "Id", "Name", Model.ParentCategoryId), "-- Select --")
How do I create a dropdown list in the controller or view model and pass it to the view? I need the "-- Select --" option to have a value of 0.

In your model, change the IList<Category> to SelectList and then instantiate it like this...
List<ParentCategory> parentCategories = categoryService.GetParentCategories();
parentCategories.Insert(0, new ParentCategory(){ Id = "0", Name = "--Select--"});
ParentCategories = new SelectList(parentCategories, "Id", "Name");
Then in your view you can simply call
#Html.DropDownListFor(m => m.ParentCategoryId, Model.ParentCategories);

One way I've seen it done is to create an object to wrap the id and value of the drop down item, like a List<SelectValue>, and pass it in your ViewModel to the view and then use an HTML helper to construct the dropdown.
public class SelectValue
{
/// <summary>
/// Id of the dropdown value
/// </summary>
public int Id { get; set; }
/// <summary>
/// Display string for the Dropdown
/// </summary>
public string DropdownValue { get; set; }
}
Here is the view model:
public class TestViewModel
{
public List<SelectValue> DropDownValues {get; set;}
}
Here is the HTML Helper:
public static SelectList CreateSelectListWithSelectOption(this HtmlHelper helper, List<SelectValue> options, string selectedValue)
{
var values = (from option in options
select new { Id = option.Id.ToString(), Value = option.DropdownValue }).ToList();
values.Insert(0, new { Id = 0, Value = "--Select--" });
return new SelectList(values, "Id", "Value", selectedValue);
}
Then in your view you call the helper:
#Html.DropDownList("DropDownListName", Html.CreateSelectListWithSelect(Model.DropDownValues, "--Select--"))

Related

Populate DropDownList in ASP.NET MVC from database table using Entity Framework 6 and ViewModel

I have been scratching my head for a whole night on an issue I can do quickly using ajax/jquery and stored procedures. I want to
1) Populate a drop down list from values obtained from a database table using Entity Framework and view model. I DO NOT WANT TO USE VIEWBAG OR VIEWDATA. Any help appreciated.
2) How can I generate a Create View using the View Model with the all the default fields ? The scaffholding works on a model but not on a view model ?
MY MODELS
public class Employee
{
public int EmployeeID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
public string Level { get; set; }
public int DepartmentId { get; set; }
}
public class Grade
{
public int ID { get; set; }
public string Level { get; set; }
}
View Model
public class GradeSelectListViewModel
{
public Employee Employee { get; set; }
public IEnumerable<SelectListItem> Grades { get; set; }
public GradeSelectListViewModel(Employee employee, IEnumerable grades)
{
Employee = employee;
Grades = new SelectList(grades, "Grade", "Name", employee.Level);
}
}
MY CONTEXT CLASS
public class EmployeeContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<Grade> Grades { get; set; }
}
MY CONTROLLER
public ActionResult Edit (int? id)
{
using (var db = new EmployeeContext())
{
var model = new GradeSelectListViewModel(db.Employees.Find(id), db.Grades);
//model.Employee = db.Employees.Single(x => x.EmployeeID == id);
model.Grades = db.Grades.ToList().Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Level
});
return View(model);
}
}
MY RAZOR PAGE CSHTML
#model MVCDemo.ViewModels.GradeSelectListViewModel
....
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
....
#Html.DropDownListFor(x => Model.Employee.Level,
new SelectList(Model.Grades, "ID", "Level"),
"Select Level")
....
<input type="submit" value="Create" class="btn btn-default" />
}
The main issue is that in the view you have new SelectList(Model.Grades, "ID", "Level") but Grades is IEnumerable<SelectListItem> and SelectListItem does not contain properties named ID and Level.
However there are a a few other issues with your code. First a view model should not contain a data model, and instead your view model should be
public class GradeSelectListViewModel
{
public int? ID { get; set; } // make this ID so you do not need an input for it
public string Name { get; set; }
.... // other properties of Employee that your editing
[Required(ErrorMessage = "..")]
public int? Level { get; set; } // make value types nullable to protect against under-posting attacks
public IEnumerable<SelectListItem> Grades { get; set; }
}
and add display and validation attributes as required. Note that I deleted the constructor (you don't seem to be using it, but if you did, then you also need to include a parameter-less constructor, otherwise an exception will be thrown when submitting to the POST method. I also assume that Level should be typeof int since you binding to the int ID property of Grade.
The the code in your GET method should be
Employee employee = db.Employees.Find(id);
var model = new GradeSelectListViewModel()
{
ID = employee.EmployeeID,
Name = employee.Name,
Level = employee.Level, // convert to int?
....
Grades = db.Grades.Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Level
})
};
return View(model);
and in the view
#Html.DropDownListFor(x => Model.Level, Model.Grades, "Select Level")
Note also that in the POST method, your need to reassign the SelectList if you return the view because ModelState is invalid.
You can use the following approach that populates three DropDownListFor at the same View:
ViewModel:
public class GroupViewModel
{
public IEnumerable<SelectListItem> Schedules { get; set; }
public int ScheduleId { get; set; }
public IEnumerable<SelectListItem> Labs { get; set; }
public int LabId { get; set; }
public IEnumerable<SelectListItem> Terms { get; set; }
public int TermId { get; set; }
}
Controller:
public ActionResult Create()
{
//Populate DropDownList binding values
var model = new GroupViewModel
{
//Preselect the Lab with id 2
//LabId = 2,
Labs = repository.Labs.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
}),
Terms = repository.Terms.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
}),
Schedules = repository.Schedules.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
})
};
return View("Create", model);
}
View:
#Html.DropDownListFor(m => m.LabId, new SelectList(Model.Labs, "Value", "Text"),
"Select", new { #class = "selectpicker" })
#Html.DropDownListFor(m => m.ScheduleId, new SelectList(Model.Schedules, "Value", "Text"),
"Select", new { #class = "selectpicker" })
#Html.DropDownListFor(m => m.TermId, new SelectList(Model.Terms, "Value", "Text"),
"Select", new { #class = "selectpicker" })

Chaining multiple classes in a MVC4 view

Let's say I have a model like this (simplified from the original):
public class Location
{
public int ID { get; set; }
public string BinNumber { get; set; }
}
public class Item
{
public int ID { get; set; }
public string Description { get; set; }
public virtual Location Bin { get; set; }
}
public class LineOnPickList
{
public int ID { get; set; }
public virtual Item Item { get; set; }
}
The usual thing to do here on the LineOfPickList Create view would be to have a dropdownlist that listed all the Item Descriptions and put the selected item in the newly created LineOnPickList record when Create was clicked.
What I need to do however is show a dropdownlist of Location BinNumbers, yet still have the Item associated with that Location in the newly created LineOnPickList record.
How would that be done?
Define a view model for your drop down
public class ItemViewModel
{
public int ID { get; set; }
public string BinNumber { get; set; }
}
Then build the drop down list data in your controller action as follows
public class CreateLineOnPickListViewModel
{
public int ItemId { get; set; }
public IEnumerable<ItemViewModel> Items { get; set; }
}
public ActionResult Create()
{
var model = new CreateLineOnPickListViewModel();
model.Items = db.Items
.Select(i => new ItemViewModel { ID = i.ID, BinNumber = i.Bin.BinNumber });
return View(model);
}
Then in your view
#model CreateLineOnPickListViewModel
#Html.DropDownListFor(m => m.ItemId, new SelectList(Model.Items, "ID", "BinNumber"), "-")
Then your post action method in your controller would look like this
public ActionResult Create(CreateLineOnPickListViewModel model)
{
var item = new Item { ID = model.ItemID };
db.Items.Attach(item);
var lineOnPickList = new LineOnPickList { Item = item };
db.SaveChanges();
return View(model);
}

Get the ID of the selected item in Dropdown list

I have to save the ID of a selected item into the database. but, I always get a null value when I select an item from the dropdown.
Here is some code:
Controller:
public ActionResult Create()
{
SelectList CategoryList = new SelectList(dc.Category.ToList(), "ID", "CategoryName");
ViewData["Categories"] = CategoryList;
ViewData.Model = new AdvertModel();
return View();
}
View:
<%:Html.DropDownList("Categories", ViewData["Categories"] as SelectList, new { #class = "dropdown" })%>
MODEL: AdvertModel
public class AdvertModel
{
public Int32 ID { get; set; }
[Required(AllowEmptyStrings=false,ErrorMessage="Please enter the title of your Ad.")]
[Display(Name="Title")]
public string Title { get; set; }
[Required(AllowEmptyStrings=false,ErrorMessage="Please enter a description of your Ad.")]
[Display(Name = "Details")]
public string Details { get; set; }
[Required(AllowEmptyStrings=false,ErrorMessage="Please enter when your Ad. will be publish")]
[Display(Name = "Publish date")]
[DataType(DataType.Date)]
public DateTime PubDate { get; set; }
[Required]
public DateTime EntryDate { get; set; }
public bool AdStatus { get; set; }
[Required]
[Display(Name = "Category")]
public Category Category { get; set; }
}
And now I want to get the ID of the selected item:
public ActionResult Create(AdvertModel ad)
{
Advert nAD = new Advert();
nAD.Title = ad.Title;
nAD.Message = ad.Details;
nAD.PublishDate = ad.PubDate;
nAD.Category = ad.Category.ID;// here I always get null.
dc.Advert.AddObject(nAD);
dc.SaveChanges();
return View(ad);
}
Any idea where am I doing wrong??
The first parameter of The Html.DropDownList is the HTML Id.
Add a CategoryId to your ViewModel and change your Dropdown List to:
<%:Html.DropDownList("CategoryId", ViewData["Categories"] as SelectList, new { #class = "dropdown" })%>
Or this might work with your current code (but not tested):
<%:Html.DropDownList("Category_ID", ViewData["Categories"] as SelectList, new { #class = "dropdown" })%>

MVC3 - Getting to Grips with the DropDownList

I'm new to MVC, so bear with me...
I've got my new form\view working (Creating and Adding a client)
But now I want to get the user so specifiy the Country where the new client is from A drop downlist. But im to sure how I to do this?
ViewModel
public class ClientNew
{
public string Company { get; set; }
public string Address { get; set; }
//New
public IEnumerable<CountryList> Country{ get; set; }
}
public class CountryList
{
public string Id { get; set; }
public string Name { get; set; }
}
Controller
(This is where is may be wrong, and is this the best way to do it?)
public ActionResult New()
{
var cl= new List<CountryList>();
cl.Add(new CountryList(){Id = "abcd",Name = "UK"});
cl.Add(new CountryList() { Id = "abce", Name = "USA" });
var model = new ViewModels.ClientNew();
model.Country= cl;
return View("New", model);
}
View (not sure how to plumb this in)
Html.DropDownList("Id" ??????)
In your view you will set up your dropdown on the property Id. This will be the current value selected in the dropdown when you POST to your form. The data that will be used for the dropdown is a SelectList called Countries that exists in your model.
#Html.DropDownListFor(m => m.Id, Model.Countries)
Your view model will have your Id, Name and Countries properties plus whatever else you need.
public class ClientNewViewModel {
public string Id { get; set; }
public string Name { get; set; }
public SelectList Countries { get; set; }
}
In your controller you need to pass the model to the view. You will need to populate the Countries SelectList. Keep in mind you will need to populate this value when you POST and fail validation as well.
public ActionResult New()
{
var model = new ClientNewViewModel();
model.Countries = new SelectList(service.GetCountries(),
"Id", "Name"); // set up what properties are used for id/name of dropdown
return View(model);
}
[HttpPost]
public ActionResult New(ClientNewViewModel model)
{
if( !ModelState.IsValid )
{
model.Countries = new SelectList(service.GetCountries(),
"Id", "Name");
return View(model);
}
// redirect on success
return RedirectToAction("Index");
}
Html.DropDownList("Id",
Country.Select(x => new SelectListItem
{
Text = x.Name,
Value = x.Id
}));
There's a good blog post on the in's and out's of how to do this here -> http://277hz.co.uk/Blog/Show/10/drop-down-lists-in-mvc--asp-net

How can I use DropDownListFor() on a dynamic type?

I get the following error in the DropDownListFor() "An expression tree may not contain a dynamic operation" because the lambda uses a dynamic type.
How can I set the selected option on the DropDownList without resorting to jQuery?
I would also rather not make a template or custom helper.
Model
public class Thing : Base {
public virtual Nullable<int> OptionID { get; set; }
public virtual Option Option { get; set; }
}
public class Option : Base {
public virtual ICollection<Thing> Things { get; set; }
}
public class Base {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
Controller
public ActionResult Edit(int Id) {
return View(new ViewModel(context, new Thing()));
}
View
#model MvcApp7.Models.ViewModel
#{
var Entity = (dynamic)Model.Entity;
}
#Html.DropDownListFor(x => Entity.OptionID , (System.Web.Mvc.SelectList)Model.Options)
ViewModel
public class ViewModel {
public ViewModel(Context context, object entity) {
this.Entity = entity;
this.Options = new SelectList(context.Options, "Id", "Name");
}
public dynamic Entity { get; set; }
public SelectList Options { get; set; }
}
EDIT: Please excuse me. I forgot that I could specify the selected option in the SelectList itself. I moved the responsibility into the ViewModel and will try to deal with it from there. However, it would still be good to know how to work around this in the View itself in case it was necessary.
I did this in the ViewModel
this.Options = new SelectList(context.Options, "Id", "Name", this.Entity.OptionID);
and this in the View
#Html.DropDownList("OptionID", Model.Options)
View
#model MvcApp7.Models.ViewModel
#Html.DropDownListFor(x => x.Entity.OptionID , (System.Web.Mvc.SelectList)Model.Options)
ViewModel
public class ViewModel {
public ViewModel(Context context, object entity) {
this.Entity = entity;
this.Options = new SelectList(context.Options, "Id", "Name");
}
public dynamic Entity { get; set; }
public SelectList Options { get; set; }
}

Resources