Populating Dropdowns in ASP.NET MVC 3 - asp.net-mvc-3

I need to populate a dropdown in ASP.NET MVC 3. I was hoping to get the answers to the following questions:
What options do I have. I mean what's the difference between #Html.DropDownList and #Html.DropDownListFor. Also are there any other options?
I have the following classes/code. What would be the razor code/HTML syntax I need (I have included what I was trying) in my .cshtml assuming I need to only show this dropdown using the classes below.
public class SearchCriterion
{
public int Id { get; set; }
public string Text { get; set; }
public string Value { get; set; }
}
public class SearchCriteriaViewModel
{
public IEnumerable<SelectListItem> SearchCriteria { get; set; }
}
public class HomeController : Controller
{
public ActionResult Index()
{
IList<System.Web.WebPages.Html.SelectListItem> searchCriteriaSelectList =
new List<System.Web.WebPages.Html.SelectListItem>();
SearchCriteriaViewModel model = new SearchCriteriaViewModel();
//Some code to populate searchCriteriaSelectList goes here....
model.SearchCriteria = searchCriteriaSelectList;
return View(model);
}
}
//Code for Index.cshtml
#model SearchCriteriaViewModel
#{
ViewBag.Title = "Index";
}
<p>
#Html.DropDownListFor(model => model.SearchCriteria,
new SelectList(SearchCriteria, "Value", "Text"))
</p>

the right side of the lambda => has to be a simple type not the complex type modify your code like
public class SearchCriteriaViewModel
{
public int Id { get; set; }
public IEnumerable<SearchCriterion> SearchCriteria { get; set; }
}
public class SearchCriterion
{
public string Text { get; set; }
public string Value { get; set; }
}
the controller will look like
public ActionResult Index()
{
//fill the select list
IEnumerable<SearchCriteria> searchCriteriaSelectList =
Enumerable.Range(1,5).Select(x=>new SearchCriteria{
Text= x.ToString(),
Value=ToString(),
});
SearchCriteriaViewModel model = new SearchCriteriaViewModel();
//Some code to populate searchCriteriaSelectList goes here....
model.SearchCriteria = searchCriteriaSelectList;
return View(model);
}
in the view
#model SearchCriteriaViewModel
#{
ViewBag.Title = "Index";
}
<p>
#Html.DropDownListFor(model => model.Id,
new SelectList(model.SearchCriteria , "Value", "Text"))
</p>

After extensively using ASP.NET MVC for the past 3 years, I prefer using additionalViewData from the Html.EditorFor() method more.
Pass in your [List Items] as an anonymous object with the same property name as the Model's property into the Html.EditorFor() method.
The benefit is that Html.EditorFor() method automatically uses your Editor Templates.
So you don't need to provide CSS class names for your Drop Down Lists.
See comparison below.
//------------------------------
// additionalViewData <=== RECOMMENDED APPROACH
//------------------------------
#Html.EditorFor(
m => m.MyPropertyName,
new { MyPropertyName = Model.ListItemsForMyPropertyName }
)
//------------------------------
// traditional approach requires to pass your own HTML attributes
//------------------------------
#Html.DropDown(
"MyPropertyName",
Model.ListItemsForMyPropertyName,
new Dictionary<string, object> {
{ "class", "myDropDownCssClass" }
}
);
//------------------------------
// DropDownListFor still requires you to pass in your own HTML attributes
//------------------------------
#Html.DropDownListFor(
m => m.MyPropertyName,
Model.ListItemsForMyPropertyName,
new Dictionary<string, object> {
{ "class", "myDropDownCssClass" }
}
);
If you want more details, please refer to my answer in another thread here.

Related

more models on a mvc3 page

Could I have more models on a razor page?
for example when I have more grid controls each with an area(a template) for editing the data,and after that i want to save the data and see it in the grid.
You can do something like the example below (this is a very over simplified example):
public class AnimalDataViewModel
{
public List<Dog> DogData { get; set; }
public List<Cat> CatData { get; set; }
public List<Mouse> MouseData { get; set; }
public AnimalDataViewModel()
{
this.DogData = new List<Dog>();
this.CatData = new List<Cat>();
this.MouseData = new List<Mouse>();
}
}
Then in your action method:
public ActionResult DisplayAnimalDataGrids()
{
AnimalDataViewModel model = new AnimalDataViewModel();
model.DogData = this.myDataService.GetDogData();
model.CatData = this.myDataService.GetCatData();
model.MouseData = this.myDataService.GetMouseData();
return View(model);
}
Then in your view:
#model AnimalDataViewModel
#Html.Grid(Model.DogData)
#Html.Grid(Model.CatData)
#Html.Grid(Model.MouseData)

how to bind a dropdownlist to model properly to be able to pass values back from view to controller

I am trying to update a compound page model which as one of its properties has a list of objects.
My Model looks like this:
public class PageViewModel
{
public ProgramListVM ProgramsDDL { get; set; }
public PageViewModel()
{
this.ProgramsDDL = new ProgramListVM();
}
}
The ProgramListVM class is:
public class ProgramListVM
{
public List<ProgramVM> Program_List { get; set; }
public int SelectedValue { get; set; }
public ProgramListVM()
{
this.Program_List = new List<ProgramVM>();
this.SelectedValue = 0;
}
}
and ProgramVM is:
public class ProgramVM
{
public int ProgramID { get; set; }
public string ProgramDesc { get; set; }
public ProgramVM(int id, string code)
{
this.ProgramID = id;
this.ProgramDesc = code;
}
}
I try to render this dropdownlist by the following two:
1-
<%: Html.DropDownList("ProgramsDDL", new SelectList(Model.Page6VM.ProgramsDDL.Program_List, "ProgramID", "ProgramDesc", Model.Page6VM.ProgramsDDL.SelectedValue))%>
2-
<%: Html.DropDownListFor(m => m.Page6VM.ProgramsDDL.Program_List, new SelectList(Model.Page6VM.ProgramsDDL.Program_List, "ProgramID", "ProgramDesc"), Model.Page6VM.ProgramsDDL.SelectedValue)%>
But when I try to update my model through a controller action
[HttpPost]
public ActionResult UpdateUser(PageViewModel model)
{
}
model.ProgramsDDL.count is zero.
What is the best way to render this dropdownlist and be able to set the selected index, and also be able to send the selected index back to the controller?
You mixed up the parameters for Html.DropDownListFor(). Code sample below should work.
<%: Html.DropDownListFor(m => m.SelectedValue,
new SelectList(Model.Page6VM.ProgramsDDL.Program_List, "ProgramID", "ProgramDesc"),
null) %>
You also should have a SelectedValue in your model that's posted back.
public class PageViewModel
{
public ProgramListVM ProgramsDDL { get; set; }
public int SelectedValue { get; set; }
public PageViewModel()
{
this.ProgramsDDL = new ProgramListVM();
}
}
Also default model binder can't map complex collections to your model. You probably don't need them in your post action anyway.

html.dropdownlistfor() troubles...getting null reference exceptions

I've tried to follow a few examples from here and a couple other resources to just create a very simple member in my viewmodel and display it as a dropdown list on my view with a dropdownlistfor() helper. I can't seem to wrap my head around it and it's not working with what I'm trying.
here's my viewmodel:
public class Car
{
public int CarId { get; set; }
public string Name { get; set; }
}
public class MyViewModel
{
public IEnumerable<Car> Cars = new List<Car> {
new Car {
CarId = 1,
Name = "Volvo"
},
new Car {
CarId = 2,
Name = "Subaru"
}
};
public int MyCarId { get; set; }
}
and here is my view:
#Html.DropDownListFor(m => m.MyCarId, new SelectList(Model.Cars, "CarId", "Name"))
and here is my controller:
public ActionResult MyView()
{
return View();
}
You need to make sure you send the Model to your View:
public ActionResult Index()
{
var myViewModel = new MyViewModel()
return View(myViewModel);
}
And in your View you need to make sure you're defining your Model:
#model namespace.MyViewModel
You example works fine, I think you forgot to send MyViewModel in POST Action.
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}

Dropdownlist using LINQ/MVC3/C# problem getting it to bind

I am super new to MVC3 and C#, so excuse my noob questions. I have been struggling with this for almost a full day and hope someone can shed some light (I have scoured this site for clues, hints, answers as well).
I have a single table in my database which will hold all the data. It is for a profile editor which will store values that the user can populate their timekeeping entry form automatically upon select. I am on step one though, trying to populate the first dropdownlist with the profile name. I am using LINQ, MVC3/ Razer, and C#.
Here is my dbml:
Cant post image cause I am new
http://imageshack.us/photo/my-images/560/timem.png/
Here is my model:
namespace Timekeeping.Models
{
public class Profile
{
public int Profile_ID { get; set; }
public string profilename { get; set; }
public string networkuserid { get; set; }
public int projectnumber { get; set; }
public int costcode { get; set; }
public int paycode { get; set; }
public int jobtype { get; set; }
public int workorder { get; set; }
public int activity { get; set; }
public string taxarea { get; set; }
public IEnumerable<Profile> profiles { get; set; }
}
public class ProfileViewModel
{
public int Profile_ID { get; set; }
public IEnumerable<SelectListItem> profiles { get; set; }
}
}
Here is my Controller:
namespace Timekeeping.Controllers
public class TimeProfileController : Controller
{
private static String strConnString = ConfigurationManager.ConnectionStrings["timekeepingConnectionString"].ConnectionString;
[HttpGet]
public ActionResult ProfileSelect()
{
profileConnectionDataContext dataContext = new profileConnectionDataContext(strConnString);
var model = new ProfileViewModel();
var rsProfile = from fbs in dataContext.TimeProfiles select fbs;
ViewData["ProfileList"] = new SelectList(rsProfile, "Profile_ID", "profilename");
return View(model);
}
}
And here are all the different html helpers I have tried for my View(none work):
#Html.DropDownList("rsProfile", (SelectList)ViewData["ProfileList"]))
#Html.DropDownListFor(
x => x.Profile_ID,
new SelectList(Model.profiles, "Values", "Text"),
"-- Select--"
)
#Html.DropDownListFor(model => model.Profile_ID, Model.profilename)
I know this is a mess to look at, but I am hoping someone can help so I can get on with the hard parts. Thanks in advance for any help I get from the community
Hope it will work surely...
Inside Controller :
var lt = from result in db.Employees select new { result.EmpId, result.EmpName };
ViewData[ "courses" ] = new SelectList( lt, "EmpId", "EmpName" );
Inside View :
<%: Html.DropDownList("courses") %>
Try this:
public class TimeProfileController : Controller
{
private static String strConnString = ConfigurationManager.ConnectionStrings["timekeepingConnectionString"].ConnectionString;
[HttpGet]
public ActionResult ProfileSelect()
{
var dataContext = new profileConnectionDataContext(strConnString);
var profiles = dataContext.TimeProfiles.ToArray().Select(x => new SelectListItem
{
Value = x.Profile_ID,
Text = x.profilename
});
var model = new ProfileViewModel
{
profiles = profiles
};
return View(model);
}
}
and in the view:
#model ProfileViewModel
#Html.DropDownListFor(
x => x.Profile_ID,
new SelectList(Model.profiles, "Values", "Text"),
"-- Select--"
)
If you are using a model class just try this:
<%: Html.DropDownList("EmpId", new SelectList(Model, "EmpId", "EmpName")) %>
If you want to add click event for drop down list try this:
<%: Html.DropDownList("courses", ViewData["courses"] as SelectList, new { onchange = "redirect(this.value)" }) %>
In the above one redirect(this.value) is a JavaScript function

How to update a model that contains a list of IMyInterface in MVC3

I have a model like so:
return new MyViewModel()
{
Name = "My View Model",
Modules = new IRequireConfig[]
{
new FundraisingModule()
{
Name = "Fundraising Module",
GeneralMessage = "Thanks for fundraising"
},
new DonationModule()
{
Name = "Donation Module",
MinDonationAmount = 50
}
}
};
The IRequireConfig interface exposes a DataEditor string property that the view uses to pass to #Html.EditorFor like so:
#foreach (var module in Model.Modules)
{
<div>
#Html.EditorFor(i => module, #module.DataEditor, #module.DataEditor) //the second #module.DataEditor is used to prefix the editor fields
</div>
}
When I post this back to my controller TryUpdateModel leaves the Modules property null. Which is pretty much expected since I wouldnt expect it to know which concrete class to deserialize to.
Since I have the original model still available when the post comes in I can loop over the Modules and get their Type using .GetType(). It seems like at this point I have enough information to have TryUpdateModel try to deserialize the model, but the problem is that it uses a generic type inference to drive the deserializer so it does not actually update any of the properties except the ones defined in the interface.
How can I get update my Modules array with their new values?
If any particular point isnt clear please let me know and I will try to clarify
You could use a custom model binder. Assuming you have the following models:
public interface IRequireConfig
{
string Name { get; set; }
}
public class FundraisingModule : IRequireConfig
{
public string Name { get; set; }
public string GeneralMessage { get; set; }
}
public class DonationModule : IRequireConfig
{
public string Name { get; set; }
public decimal MinDonationAmount { get; set; }
}
public class MyViewModel
{
public string Name { get; set; }
public IRequireConfig[] Modules { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
Name = "My View Model",
Modules = new IRequireConfig[]
{
new FundraisingModule()
{
Name = "Fundraising Module",
GeneralMessage = "Thanks for fundraising"
},
new DonationModule()
{
Name = "Donation Module",
MinDonationAmount = 50
}
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
View:
#model MyViewModel
#using (Html.BeginForm())
{
#Html.EditorFor(x => x.Name)
for (int i = 0; i < Model.Modules.Length; i++)
{
#Html.Hidden("Modules[" + i + "].Type", Model.Modules[i].GetType())
#Html.EditorFor(x => x.Modules[i])
}
<input type="submit" value="OK" />
}
and finally the custom model binder:
public class RequireConfigModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var typeParam = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Type");
if (typeParam == null)
{
throw new Exception("Concrete type not specified");
}
var concreteType = Type.GetType(typeParam.AttemptedValue, true);
var concreteInstance = Activator.CreateInstance(concreteType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => concreteInstance, concreteType);
return concreteInstance;
}
}
which you would register in Application_Start:
ModelBinders.Binders.Add(typeof(IRequireConfig), new RequireConfigModelBinder());
Now when the form is submitted the Type will be sent and the model binder will be able to instantiate the proper implementation.

Resources