MVC: Best way to populate Html .DropDownList - asp.net-mvc

I'm looking for a sound philosophy for bringing dynamic data into a view to populate a dropdownlist. Would it be a good idea to create a model object for dropdownlists and other "overhead" data or use a viewbag?
Thanks

Example for guidance:
I think the best way to achieve what you're after would be to use a ViewModel. You'd load the stuff you want to display in your View through this. So you'd create a dropdownlist with your accountlist which will be loaded in your controller. You'll also have your IEnumerable PErsoncontact in there which will also be loaded in your controller. Then your controller will pass the ViewModel to the View. You can use this as a guide.
ViewModel:
public class PersonViewModel
{
public int PersonID {get;set;}
public List<SelectListItem> PersonContactList {get;set;}
public IEnumerable<TypesAvail> TypesAvails{get;set;}
}
Dropdownlist in Razor View :
#Html.DropDownListFor(m => m.PersonID , Model.PersonContactList )
Edit:-
This is an example .Yes you can create a new class in same Model.
public class TypesAvail
{
public String TypeNme { get; set; }
public long TypeID { get; set; }
public int NumSelected { get; set; }
public int TypeCount { get; set; }
public IEnumerable<SelectListItem> CarsAvail
{
get
{
return new SelectList(
Enumerable.Range(0, TypeCount+1)
.OrderBy(typecount => typecount)
.Select(typecount => new SelectListItem
{
Value = typecount.ToString(),
Text = typecount.ToString()
}), "Value", "Text");
}
}
}
Dropdownlist in Razor View :
#Html.DropDownListFor(m=> m.NumSelected, Model.CarsAvail)

Using the ViewBag (as some have suggested in other answers/comments) to get data from your controller to view is generally seen as a code lack.
Your ViewModel should ideally contain all of the data you need for your view. So use your controller to populate this data on a property of your ViewModel:
Here is a simple example of how to create a drop down list in ASP.NET MVC using Html.DropDownListFor using model.
You can do it like this all inlined in your *.cshtml file like so:
#Html.DropDownListFor(model => model.Package.State, new SelectList(
new List<Object>{
new { value = 0 , text = "Red" },
new { value = 1 , text = "Blue" },
new { value = 2 , text = "Green"}
},
"value",
"text",
2))
which will create like this:
<select id="Package_State" name="Package.State"><option value="0">Red</option>
<option value="1">Blue</option>
<option value="2">Green</option>
</select>
Refer to this answer for more information

Including the data in the View's Model or in the ViewBag are both good options, the best one depends entirely on your specific use case.
If this dropdown should be included on only one (or just a few) pages, it makes sense to be part of the ViewModel.
If every page should have the dropdown (if it's part of the menu, or footer for instance) you could create a BaseController that supplies ViewBag data for the dropdown, and let your other controllers inherit from that:
BaseController.cs
public class BaseController : Controller
{
public BaseController() {
ViewBag.MyDroprown = ...
}
}
Any other controller
// inheriting from BaseController will make ViewBag.MyDroprown accessible in the View
public class HomeController : BaseController
{
// Any actions here
}

In my opinion View model should contain all the data that is needed for rendering the view and that is available on view creation.
Using ViewBag for me is like using dynamic type in code - it gives you some flexibility but comes with the price of possible errors, so i try to avoid as much as possibe

Related

Multiple Dropdown Lists, Multiple Models

I have a few entities that I want to fill into a few dropdown lists on a single form. Which is the best way to go about doing so. For multiple models in a single view I've created a viewmodel and threw the entities into it but how can I bring back the list in the database say for entity "Network" and fill the dropdown with "Name" and "NetworkID"?
First create the Model:
public class Data
{
public List<tbl_Dept> lstDepatrment;
public List<tbl_employees> lstEmployee;
//other
}
Then just Create a View
#model MVCApp.Models.Data
#{
var categoryList = Model.lstDepatrment.Select(cl => new SelectListItem
{
Value = cl.Dept_ID.ToString(),
Text = cl.Dept_Description == null ? String.Empty : cl.Dept_Description
});
//list for other Drop Down
}
#(Html.DropDownList("sampleDropdown", categoryList, "-----Select-----"))
You can do as follows:
Designing your model:
Prepare Select List for as many dropdowns you want
For eg:
Public class ModelName
{
...// Properties
public IEnumerable<SelectListItem> ListName1 { get; set; }
public IEnumerable<SelectListItem> ListName2 { get; set; }
public IEnumerable<SelectListItem> NetWorkList { get; set; }
... //etc
}
Prepare and bind List to Model in Controller :
public ActionResult Index(ModelName model)
{
var networks = // Your network List
model.NetWorkList = networks.Select(x=> new SelectListItem() {
Text = x.Name,
Value = x.NetworkID
});
..// Same as above prepare the list for other dropdowns
return View(model);
}
Then in your view prepare your dropdown as follows:
#Html.DropDownListFor(m => Model.NetworkID,Model.NetWorkList)
Well in that case you can keep all the model list data in somewhere in java script model and then using the JQuery you can bind all of Dropdown controls with same model list.
Alternatively you can fetch that data using Ajax and bind those Dropdowns there in java script and retrieve the value rather then throwing data multiple list from controller.

Queries realted to Dropdown list in MVC

I am a new to ASP.NET MVC, I am developing an application. I want to bind the data in the drop down list in create view.
How to bind the data in the drop down? I have go through many question and answers here...
I have seen usually everyone suggested to use List<SelectListItem> what is its purpose?
Do I need to use ViewModel while binding the data to drop down list?
Can I get simple example where data get bind in the dropdown using viewbag?
I have created a list in controller
List<string> items = new List<string>();
and I want to pass this list to view using viewbag and simply want to bind to drop down list.
How to do this ?
I'd suggest using a ViewModel as it makes interaction with user input so much easier. Here's an example of how you might bind data from your ViewModel to a drop down in your View. First, the ViewModel:
public class CrowdViewModel
{
public string SelectedPerson { get; set;}
public IEnumerable<SelectListItem> People { get; set; }
}
So yes, you're right - use a collection of SelectListItems. I'm guessing in your case, the SelectListItem's Value and Text property will be the same. You could turn your List into IEnumerable like this:
[HttpGet]
public ActionResult Home()
{
// get your list of strings somehow
// ...
var viewModel = new CrowdViewModel
{
People = items.Select(x => new SelectListItem { Text = x, Value = x })
}
return View(viewModel);
}
Now you need to bind that ViewModel's property to the DropDown on your view. If you're using the Razor ViewEngine, the code will look something like this:
#model MyApp.ViewModels.CrowdViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(model => model.SelectedPerson, Model.People)
}
Now when you post that form, MVC will bind the selected value to the ViewModel's SelectedPerson property!
[HttpPost]
public ActionResult Home(CrowdViewModel viewModel)
{
// viewModel.SelectedPerson == whatever the user selected
// ...
}
Easy as that!
Update:
If you really want to use the ViewBag (don't do it), you can pass your list through from your Controller action like so:
[HttpGet]
public ActionResult Home()
{
ViewBag.People = new List<string> { "Bob", "Harry", "John" };
return View();
}
And then create a SelectList on your View:
#Html.DropDownList("SelectedPerson", new SelectList(ViewBag.People, Model))

How do I add a Custom Query for a drop down and retain the View Model Pattern?

I've read many articles which they state that querying should not be placed in the Controller, but I can't seem to see where else I would place it.
My Current Code:
public class AddUserViewModel
{
public UserRoleType UserRoleType { get; set; }
public IEnumerable<SelectListItem> UserRoleTypes { get; set; }
}
public ActionResult AddUser()
{
AddUserViewModel model = new AddUserViewModel()
{
UserRoleTypes = db.UserRoleTypes.Select(userRoleType => new SelectListItem
{
Value = SqlFunctions.StringConvert((double)userRoleType.UserRoleTypeID).Trim(),
Text = userRoleType.UserRoleTypeName
})
};
return View(model);
}
The View:
<li>#Html.Label("User Role")#Html.DropDownListFor(x => Model.UserRoleType.UserRoleTypeID, Model.UserRoleTypes)</li>
How do I retain the View Model and Query and exclude the User Type that should not show up?
I think that you are doing it just fine.
Any way... all you can do to remove the querying logic from controller is having a ServiceLayer where you do the query and return the result.
The MVC pattern here is used correctly... what your are lacking is the other 2 layers (BusinessLayer and DataAccessLayer)... since ASP.NET MVC is the UI Layer.
UPDATE, due to comment:
Using var userroletypes = db.UserRoleTypes.Where(u=> u.UserRoleType != 1);
is OK, it will return a list of UserRoleType that satisfy the query.
Then, just create a new SelectList object using the userroletypes collection... and asign it to the corresponding viewmodel property. Then pass that ViewModel to the View.
BTW, I never used the db.XXXX.Select() method before, not really sure what it does... I always use Where clause.
SECOND UPDATE:
A DropDownList is loaded from a SelectList that is a collection of SelectItems.
So you need to convert the collection resulting of your query to a SelectList object.
var userroletypes = new SelectList(db.UserRoleTypes.Where(u=> u.UserRoleType != 1), "idRoleType", "Name");
then you create your ViewModel
var addUserVM = new AddUserViewModel();
addUserVM.UserRoleTypes = userroletypes;
and pass addUserVM to your view:
return View(addUserVM );
Note: I'm assuming your ViewModel has a property of type SelectList... but yours is public IEnumerable<SelectListItem> UserRoleTypes { get; set; } so you could change it or adapt my answer.
I don't see anything wrong with your code other than this db instance that I suppose is some concrete EF context that you have hardcoded in the controller making it impossible to unit test in isolation. Your controller action does exactly what a common GET controller action does:
query the DAL to fetch a domain model
map the domain model to a view model
pass the view model to the view
A further improvement would be to get rid of the UserRoleType domain model type from your view model making it a real view model:
public class AddUserViewModel
{
[DisplayName("User Role")]
public string UserRoleTypeId { get; set; }
public IEnumerable<SelectListItem> UserRoleTypes { get; set; }
}
and then:
public ActionResult AddUser()
{
var model = new AddUserViewModel()
{
UserRoleTypes = db.UserRoleTypes.Select(userRoleType => new SelectListItem
{
Value = SqlFunctions.StringConvert((double)userRoleType.UserRoleTypeID).Trim(),
Text = userRoleType.UserRoleTypeName
})
};
return View(model);
}
and in the view:
#model AddUserViewModel
<li>
#Html.LabelFor(x => x.UserRoleTypeId)
#Html.DropDownListFor(x => x.UserRoleTypeId, Model.UserRoleTypes)
</li>

Reusable DropDownList Content

I'm fairly new to ASP.NET MVC and am looking for help with the following issue.
I have a DropDownList control in a view. The selected value will be stored in an integer field of my model.
My preference is to not hard code the text and values in markup. In addition, I'd like to be able to use this same list of text and values in DropDownList controls in other views.
I'm not sure if I need to create a class that initializes these values somewhere, or perhaps I need an extension method. I could use some guidance on the best way to approach this.
This is a sample:
var apps = _webAppRepo.GetAll();
IList<SelectListItem> appSelectListItems = new List<SelectListItem>();
foreach (var item in apps) {
appSelectListItems.Add(new SelectListItem {
Text = item.ApplicationName,
Value = item.WebApplicationID.ToString()
});
}
ViewBag.AppSelectListItems = appSelectListItems;
And this is how you use it on you view:
#Html.DropDownListFor(model =>
model.WebApplicationID,
(IEnumerable<SelectListItem>)ViewBag.AppSelectListItems
)
If you would like to use it without a model, this is the way:
#Html.DropDownList("Foo",
(IEnumerable<SelectListItem>)ViewBag.AppSelectListItems
)
There are a number of ways of doing this, but you could do worse than storing these values in a view model, and rendering them on the page. I'm just using a Tuple here as an example:
public class MyViewModel
{
List<Tuple<int, string>> items_ = new List<Tuple<int, string>>();
public MyViewModel()
{
items_.Add(new Tuple<int, string>(1, "Item1"));
items_.Add(new Tuple<int, string>(2, "Item2"));
// etc
}
public List<Tuple<int, string>> Items { get { return items_; } }
}
Your controller:
public class MyController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
}
Your view:
#model MyNameSpace.MyViewModel
<select id="mySelect" name="mySelect>
#{foreach(Tuple<int, string> item in Model.Items){
<option value="#item.Item1">#item.Item2</option>
}}
</select>
Obviously, you can also make an extention method to create combo boxes in more interesting ways :)
You should populate your DropDownList from a database table, or from memory o reading from a xml file.
The you should be able to use the same data to populate any other ddl on your views.

Templated Helpers and SelectLists in the View Model don't mix: true?

It seems like there's a disconnect in the advised best practices when it comes to including the data source of a select list in a view model. For example, many best practices blog posts will recommend something along these lines:
ViewModel:
public class InvoiceViewModel
{
[UIHint("SelectInvoiceType")]
public int idInvoiceType { get; set; }
/* snip */
/* I'll use this in the view to generate a SelectList */
public List<invoicetype> InvoiceTypes { get; set; }
}
But then when we get to the editor template, the Model object will be just the int, with no knowledge of the containing view model:
SelectInvoiceType.cshtml
#model int
#{
Layout = "~/Views/Shared/_EditorFormItem.cshtml";
List<SelectListItem> selList = /* nothing to say here, really */;
}
#section DataContent {
#Html.DropDownListFor(m => Model, selList, null)
}
So, unless I'm missing something, these two "best practices" -- templated view helpers and strongly-typed list data in the view model -- just can't be used together. You have to resort to stuffing your list data into the ViewBag. Sound about right?
Sorry to sound incredulous, but I feel like I must be missing something.
You have to resort to stuffing your list data into the ViewBag. Sound about right?
No. To me stuffing things in ViewBag/ViewData doesn't sound right. You should not use int as a model type to an editor template that is supposed to generate a dropdownlist. A dropdownlist consists of two properties: a scalar type to bind the selected value to and a collection to be used to generate the different options in this ddl.
So a more correct way would be the following:
public class MyViewModel
{
[UIHint("SelectInvoiceType")]
public InvoiceTypesViewModel Invoice { get; set; }
... some other properties specific to the view
}
where InvoiceTypesViewModel is a view model and doesn't contain any reference to domain models such as invoicetype in the list in your example:
public class InvoiceTypesViewModel
{
public int SelectedInvoiceType { get; set; }
public SelectList InvoiceTypes { get; set; }
}
then in your main view:
#model MyViewModel
...
#Html.EditorFor(x => x.Invoice)
and the editor template:
#model InvoiceViewModel
#Html.DropDownListFor(m => m.SelectedInvoiceType, Model.InvoiceTypes)

Resources