ASP.Net MVC Drop Down List - asp.net-mvc

I am developing an ASP.Net MVC 3 Web application and believe my method of returning a list of items to a drop down list in the View is a bit long winded. Let me explain.
I have a ViewModel which contains an Equipment Entity and a SelectList to display a list of Categories.
public class AddEquipmentViewModel
{
public Equipment equipment { get; set; }
public SelectList categoryList { get; set; }
}
In the GET create method of my Equipment Controller, I return my ViewModel to the view, see below:
//Add new select list item named 'Please select option' to the top of list
var categoryList = categoryService.GetAllCategories();
var categorySelectListItems = categoryList.Select(c => new SelectListItem { Value = c.categoryID.ToString(), Text = c.categoryTitle }).ToList();
categorySelectListItems.Insert(0, new SelectListItem { Text = "Please select option", Value = string.Empty });
AddEquipmentViewModel viewModel = new AddEquipmentViewModel
{
equipment = new Equipment(),
categoryList = new SelectList(categorySelectListItems.ToList(), "Value", "Text")
};
I know I could discard the extra code before I create an instance of my ViewModel and just assign my Category List to the relevant ViewModel property like so
categoryList = new SelectList(categoryService.GetAllCategories(), "categoryID", "categoryTitle")
However, this then just returns a list of categories to my drop down list in my View, whereas, I would like to add a new SelectListItem, ie, "Please select option".
I just feel that my approach to manually adding a new SelectListItem to my SelectList is a bit cumbersome and I would greatly appreciate if someone could share a better method?
Thanks for your time.

<%= Html.DropDownList("name", new SelectList(...), "Your Combobox default message")%>
Hope it helps

Related

Dropdownlist client side required validation (without model)

View:
#Html.DropDownList("CategoryItems", null, new { #class = "ddlcs" })
#Html.ValidationMessage("CategoryItems")
Controller:
var cat = from s in db.CategoryDbSet
where s.IsActive == true
orderby s.CatName
select new { s.CatID, s.CatName };
var catListItems = cat.ToList()
.Select(c => new SelectListItem
{
Text = c.CatName,
Value = c.CatID.ToString()
})
.ToList();
catListItems.Insert(0, new SelectListItem
{
Text = "[--Select the category--]",
Value = ""
});
ViewBag.CategoryItems = catListItems;
I wish to enforce the required validation on the dropdown when someone selects the "Select the category" option during the save action. I am new to MVC framework and i am not sure where am i making the mistake ? This dropdown is not tied up with the Model.
Please suggest the soln.
This dropdown is not tied up with the Model.
That's the mistake. Validation in ASP.NET MVC works by decorating your view model properties with the respective attributes. For example if you want to make this dropdown required, you would decorate the corresponding property on your view model with the [Required] attribute.
So add the necessary properties to your existing view model:
public class MyViewModel
{
[Required]
public int? SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
... some other properties that your view might need
}
and then in your controller action populate this view model:
var model = new MyViewModel();
model.Categories = cat
.ToList()
.Select(c => new SelectListItem
{
Text = c.CatName,
Value = c.CatID.ToString()
}).ToList();
return View(model);
and in your view use the strongly typed versions of the helpers:
#Html.DropDownListFor(
x => x.SelectedCategoryId,
Model.Categories,
"[--Select the category--]",
new { #class = "ddlcs" }
)
#Html.ValidationMessageFor(x => x.SelectedCategoryId)
If you want only client side validation, you may do this:
$('form').validate({
rules:{
CategoryItems: 'required'
}
});
Working demo.
But I wouldn't suggest doing so as the client side validation is for better user experience and can be easily bypassed. The correct way to do this is described in Darin's answer, using dataannotations and view models.

Confusion on how to include a "View Model" to a "View" in ASP.NET MVC

From reading many tutorials on how to set up drop down menus on various sites I've managed to piece a few things together but am still stuck.
I've been told that my code below should be contained in a View Model, currently it is at the top of my View:
var genderItems = new List<ListItem>
{
new ListItem { Text = "Unisex", Value = "0" },
new ListItem { Text = "Female", Value = "1" },
new ListItem { Text = "Male", Value = "2" }
};
var statusItems = new List<ListItem>
{
new ListItem { Text = "Inactive", Value = "0" },
new ListItem { Text = "Active", Value = "1" }
};
In the same View I have been using this code to generate a drop down box:
#Html.DropDownList("RoomGender", new SelectList(genderItems, "Value", "Text", Model.RoomGender))
Could somebody please explain how I am supposed to abstract this and then pass it to the view without removing the already attached Room model which I have, as that is the Model which models the data for the database.
This is probably quite simple and I have tried researching it, but I really am struggling to piece it all together.
This is one is for binding Enum Gender to your view.
Suppose Student is the Model that I am binding to the View,
namespace MyApp.Models
{
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Gender Gender { get; set; }
}
public enum Gender
{ Male = 0, Female = 1 }
}
and then in your View
#Html.DropDownListFor(model => model.Gender, new SelectList(Enum.GetValues(typeof(MyApp.Models.Gender))))
I hope you get it now!
Isn't this Room model already your view model? A view model is simply a class that contains the data that your view requires. Convention has it that they tend to be called view models to separate them from domain models. In your case, you could either add a couple of properties to Room for StatusItems and GenderItems. Alternatively, create a RoomViewModel with a property Room and the 2 list properties and pass that to the View instead.
Ideally you would create a RoomViewModel and create properties for all of the data that you need to display within your view. This doesn't need to match the structure of your domain objects. In you MVC layer, you would take the domain objects that you retrieve the data from for your view, and map those properties across during view model creation. You can either do this manually or using a tool like Automapper.
In order to get the dropdown list data to the view, I would suggest adding the data to the ViewBag.
You can see an example of this here:
http://jnye.co/Posts/12/creating-cascading-dropdownlists-using-mvc-4-and-jquery
First add the values to your ViewBag. Typically i put this in it's own method as it needs to be called each time the page is loaded (including, when being displayed on a failed form subission):
//You can keep your current list setup, I have simply shortened it for brevity
var genderItems = new List<string> {"Unisex", "Female", "Male"};
ViewBag.Genders = new SelectList(genderItems);
Then in your view:
#Html.DropDownList("gender", ViewBag.Genders as SelectList)
Or if you want to bind the result to a property on your view model:
#Html.DropDownListFor(m => m.Property, ViewBag.Genders as SelectList)

MVC DropDown from DataBase

public class DropDown
{
public string[] SelectedItems { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
}
Am trying to get a DropDown in MVC from DB with above structure.
From DataBase I got the Text and value field and having in IEnumerable<T> where T has 2 properties id and text.
What is the best way convert ienumerable id to array of string and assign id, text to SelectedListItem ?
I thought of looping through the ienumerable and forming the DropDown, but thought there will be better ways.
update
For example :
In DB i have student table with
ID,
Name,
Class,
Section
And i got id and Name in ienumerable<student> . From there i need to convert into a DropDown
IEnumerable<Student> studentList = GetStudentList();
IEnumerable<SelectListItem> dropdownItems = new MultiSelectList(studentList, "ID", "Name",selectedValues);
DropDown dropDown = new DropDown { Items = dropdownItems };
If you want to create a listbox you can do it with HTML helpers like this:
#Html.ListBoxFor(item => item.SelectedStudents, new MultiSelectList(Model.StudentList, "ID", "Name",selectedValues))
I'm unsure why you are trying to create your own DropDown class, why not use the built-in MVC HTML Helper?
If you have an IEnumerable that you want to turn into a SelectList which will be consumed by the helper, something like this would work:
var selectListItems = from t in items
select new SelectListItem{
Text = t.Text,
Value = t.Id
}.ToList();
Then fire it over to your view, you could ideally use a viewmodel, but the ViewBag works too:
ViewBag.SelectListItems = selectListItems;
Finally, have your HTML Helper build your drop down for you in your view:
#Html.DropDownList("SelectListItems")
It looks like maybe you want multiple dropdowns for every array position in selectedItems? If so, I just had this problem last week. I called a foreach inside Html.DropDownListFor(...).
<% for(int i = 0; i < Model.SelectedItems.length; i++) %>
<%: Html.DropDownListFor(m => m.SelectedItems[i], Model.Items %>

asp.net mvc 3 pre-select Html.DropDownListFor not working in nerd dinner

Learning about dropdown lists, Im trying to add a RSVP create page for nerddinner as in Scott Gu's blog with a Html.DropDownListFor listing available dinners.
I can get the dropdown list populated but I cannot get the dropdown to pre select the value ("Sample Dinner 2") I want. Im using an initilizer to seed a few dinner objects in the db. The database is sql ce 4 using a EF 'code first approach'. Sorry I know this is a v common problem and hate to ask, but honestly have spent quite some time on this but cant get it to work:
ViewModel
public class RSVPViewModel
{
public SelectList DinnersList { get; set; }
public RSVP Rsvp { get; set; }
public string SelectedItem { get; set; }
}
Controller
//
//GET: /RSVP/Create
public ActionResult Create()
{
RSVP rsvp = new RSVP();
string selected = "Sample Dinner 2";
var typeList = new SelectList(dbc.Dinners.ToList(), "DinnerID", "Title", selected);
var viewModel = new RSVPViewModel { DinnersList = typeList, Rsvp = rsvp, SelectedItem = selected };
return View("Create", viewModel);
}
View
#Html.DropDownListFor(model => model.Rsvp.DinnerID, Model.DinnersList)
HTML Result
<select data-val="true" data-val-number="The field DinnerID must be a number." data-val-required="The DinnerID field is required." id="Rsvp_DinnerID" name="Rsvp.DinnerID">
<option value="1">Sample Dinner 1</option>
<option value="2">Sample Dinner 2</option>
</select>
So is not preselecting the dropdownlist with the value "Sample Dinner 2" when the page loads. The list displays ok and sets the correct DinnerID when I make a selection and click Submit.
Tries this also:
#Html.DropDownListFor(x => x.SelectedItem, Model.DinnersList)
but doesnt set or bind to Rsvp.DinnerID.
This preselects from the list but doesnt bind (or set Rsvp.DinnerID)
#Html.DropDownList("DinnersList")
I want to keep it mvc3 so want to implement with strong type using ViewModel approach (no ViewData) and preferably using Html.DropDownListFor (not Html.DropDownList).Viewbag seems unnecessary for this case.
Thanks!
Edit1
Thinking I should be using a selectList of selectListItems I tried this verbose approach :
RSVP rsvp = new RSVP();
string selected = "2";
List<SelectListItem> dinners = new List<SelectListItem>();
foreach (Dinner dinner in dbc.Dinners.ToList())
{
SelectListItem slDinner = new SelectListItem();
slDinner.Value = dinner.DinnerID.ToString();
slDinner.Text = dinner.Title;
slDinner.Selected = (slDinner.Value == selected);
dinners.Add(slDinner);
}
var dinnersList = new SelectList(dinners, "Value", "Text", selected);
var viewModel = new RSVPViewModel { DinnersList = dinnersList, Rsvp = rsvp, SelectedItem = selected };
However still no work. Should I be making use of the ViewModel SelectedItem property in: #Html.DropDownListFor.. somehow? Something like :
#Html.DropDownListFor(x => x.SelectedItem, Model.DinnersList)
but how to I get a selected value to set Rsvp.DinnerID. I think thats called binding.
After reading here and here, I finally understand how HtmlDropDownlistFor automatically selects the correct item in the dropdown based on your model - selecting a dinnerID in RSVP (foreign key to dinner.dinnerID) will cause the dropdown containing list of Dinner.DinnerIDs to pre select that value. No need yet I think for selectedValue in the SelectList or ViewModel.
Solution:
//
//GET: /RSVP/Create
public ActionResult Create()
{
//automatically preselects matching DinnerID in the Dinner dropdownlist
var rsvp = new RSVP {DinnerID = 2 };
var typeList = new SelectList(dbc.Dinners.ToList(), "DinnerID", "Title");
var viewModel = new RSVPViewModel { DinnersList = typeList, Rsvp = rsvp};
return View("Create", viewModel);
}
The SelectList constructor you're using is supposed to provide the selected value, but you are providing the selected text. You may want to try:
int selected = 2;
Html.DropDownList only works if the bound property is an int. Any other type, such as a named enum, will cause it to default to the first item.
Add a property to your Model, type int, which wraps the enum you are trying to maintain:
public myEnumType myProperty {get; set;} // don't bind this to Html.DropDownList
public myEnumType myPropertyAsInt {
get {return (int)this.myProperty; }
set {this.myProperty = (myEnumType)value; }
} // bind this instead
No need to use Selected in your SelectList - Html.DropDownList will synchronise just fine.
Please take care if there is a QUERY STRING with same name , it will override that behavior, Not sure about HIDDEN FIELDS with same name.
E.g.
DropDownListFor will use the value of Query String of DinnerID if
found
Html.DropDownList accepts int properties, DropDownListFor too, but you have to be careful what you are doing. I examined the SelectExtensions.cs from ASP.NET MVC 3 and found this:
When you use DropDownList("XyField", "default") to create a DropDown, then you must place the select list into ViewBag.XyField and DropDownList() handles this correctly.
When you use DropDownListFor(m=>m.XyField, ... ), you can pass the select list explictly, like this:
DropDownListFor(m=>m.XyField, ViewBag.XyFieldList as IEnumerable)
When you do this, this following happen:
The second parameter of DropDownListFor(...) will be used as source for the options
If there is a ModelState entry for "XyField", this will be used as the model value
If there is no model state AND Html.ViewData.Eval("XyField") returns not null, this value will be used as the model value.
If the found model value is not null, it will be converted to a string, using CultureInfo.CurrentCulture, and this value is compared with your SelectListItem values to preselect the list options.
Attention here: if you stored your select list in ViewBag.XyField, it will be found before the model is accessed. The don't want to compare "selectList.ToString()" with "selectList[i].Value" to preselect your options. Store your selection list in another place!
The funny thing is, you CAN use DropDownListFor with an implicit select list, in the same way as you expect it from DropDownList(). In this case, you will even store your list in ViewBag.XyField. To make this work, you simply have to call the helper with null as second parameter:
DropDownListFor(m=>m.XyField, null)
Then, the select list is pulled from ViewBag.XyField and step 3 in the list above is skipped. So, if XyField is in the model state, this will take precedence before your own Selected properties in the select list, but otherwise, the select list will be used "as is".
Greetings
Rolf

MVC SelectList not working

List<SelectListItem> items = new List<SelectListItem>();
if (a)
{
SelectListItem deliveryItem = new SelectListItem()
{
Selected = a.selected,
Text = "Delivery",
Value = "1"
};
items.Add(deliveryItem);
}
if (b)
{
SelectListItem pickupItem = new SelectListItem()
{
Selected = b.selected,
Text = "Pickup",
Value = "2"
};
items.Add(pickupItem);
}
SelectList selectList = new SelectList(items);
ViewData["OrderTypeList"] = selectList;
Then using it with
Html.DropDownList("OrderTypeList")
Renders
<select id="OrderTypeList" name="OrderTypeList"><option>System.Web.Mvc.SelectListItem</option>
<option>System.Web.Mvc.SelectListItem</option>
</select>
Why it is not rendering options properly?
The constructor method you're calling when you do:
SelectList selectList = new SelectList(items);
Creates a set of SelectListItems that themselves point to SelectListItems (hence the weird option since it just calls ToString on the object). Instead set your list to the ViewData key directly
ViewData["OrderTypeList"] = items;
You could have also simply changed the one line from:
SelectList selectList = new SelectList(items);
to
SelectList selectList = new SelectList(items, "Text", "Value");
This will instruct MVC which properties to use as the Text and Value in your option tags.
Or you could create a class that will hold the select list and then return the class as the views model. I think that's a much more elegant way of doing it rather than ViewData.
public class MyFormViewModel
{
public SelectList Friends { get; set; }
}
Then in your ActionResult
MyFormViewModel fvm = new MyFormViewModel();
fvm.Friends = new SelectList(myList, "UserName", "NickName");
Then in your view
<%= Html.DropDownList("ToUserName", Model.Friends, new { #class = "field" })%>
If you look at the Intellisense for the SelectList constructor overloads, the code SelectList(items) should work, but doesn't. The fact that it simply does a ToString() on items is, as far as I can tell, a bug that Microsoft should fix. The answers are all nice workarounds. BTW, if you use the method supplying "Text" and "Value", the correct answer should be
SelectList selectList = new SelectList(items, "Value", "Text")
not
SelectList selectList = new SelectList(items, "Text", "Value")
At least, that agrees with my experimentation in MVC 3.
I think you should try rendering with
Html.DropDownList("OrderTypeList", ViewData["OrderTypeList"])

Resources