I have an ASP.NET MVC 4 app. I'm not an MVC expert. In my view (.cshtml file), I have a Model that I'm binding to. In my model, I have a list of short values setup like this:
public void Load() {
List<short> options = new List<short>();
options.Add(1);
options.Add(3);
options.Add(7);
this.Options = options;
}
public List<short> Options = new List<short>() { get; set; }
public short? SelectedOption = null;
In my .cshtml file, I need to let the user choose one of the options from a drop down list. I see a bunch of HTML helpers, but I'm totally confused how to do this. How do I just display the drop down list and bind it back to my model? I am successfully binding to text boxes already, so I know I have my plumbing setup correctly. Its just this drop down list that's throwing me for a loop.
Thank you!
Suppose the object you are passing to the .cshtml view is your list which can be either passed through the ViewBag or as model.
Then depending in your requirement you can use multiple things to make a dropdown list out of which most preferable would be.
Html.DropDownList extention. Link to MSDN
so typical code would be
var options = Model ; //OR Viewbag.Options;
#Html.DropDownList(options.Select(o=>
new SelectListItem()
{
Text = o.ToString(),
Value = o.ToString()}
))
Also if you want to do it without any such specialized helper then
you can just create the HTML yourself.
<select>
#foreach(var o in Options){
<option value="#o.ToString()">#o.ToString()</option>
}
</select>
Small working snippet:
#model SelectListItem
#{
ViewBag.Title = "Index";
Layout = null;
List<SelectListItem> x = new List<SelectListItem>()
{
new SelectListItem { Text = "1", Value = "100", Selected = false },
new SelectListItem { Text = "2", Value = "200", Selected = true }
};
}
<html>
<head>
<title></title>
<script src="~/Scripts/jquery-1.8.2.js"></script>
</head>
<body>
#Html.DropDownListFor(model => model.Text, x)
</body>
</html>
<h2>Index</h2>
Above is the code of a view. You can pass a full model from the controller, when calling the View method, that will contain the list of elements you want to show. For the example, I simply created it on the fly (x list)
You can use this way for a dropdownlist..
In your controller
var sample = new List<SelectListItem> { new SelectListItem { Text = "--Select--", Value = "0" }, new SelectListItem { Text = "A", Value = "1" }, new SelectListItem { Text = "B", Value = "2" } };
ViewBag.something = sample;
In your View,
#Html.DropDownListFor(m => m.colname, (List<SelectListItem>)ViewBag.something , null, new { type = "text", Class = "", style = "" })
Related
Below is my code of
view:
#model MvcDemo.Models.viewmodelCities
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div>
#using (#Html.BeginForm())
{
#Html.ListBoxFor(x => x.SelectedCities, Model.Cities, new {
size=#Model.Cities.Count()})
<br/>
<input type="submit" value="submit" />
}
</div>
model:
public class viewmodelCities
{
public IEnumerable<SelectListItem> Cities { get; set; }
public IEnumerable<String> SelectedCities { get; set; }
}
controller action method for Get:
[HttpGet]
public ActionResult Index()
{
EmployeeDbContext db = new EmployeeDbContext();
List<SelectListItem> listSelecteditem = new List<SelectListItem>();
foreach (tblCity city in db.tblCities)
{
SelectListItem selectListItem = new SelectListItem()
{
Text = city.Name,
Value = city.ID.ToString(),
Selected = city.IsSelected
};
listSelecteditem.Add(selectListItem);
}
viewmodelCities vmc = new viewmodelCities();
vmc.Cities = listSelecteditem;
return View(vmc);
}
& controller action method for post:
[HttpPost]
public string Index(IEnumerable<string> SelectedCities)
{
if(SelectedCities==null)
{
return "You did not select any city";
}
else
{
StringBuilder sb = new StringBuilder();
sb.Append("You selected - "+string.Join(",",SelectedCities));
return sb.ToString();
}
}
In the output when i select any cities, In the post method their ID's are automatically bound to the IEnumerable.So when i select cities with Id's:3 & 4 i get the below output.
You selected - 3,4
As you can see in the whole code i'm nowhere inserting values into selectCities. Since i'm newbie into mvc and don't completely understand it's conventions can someone explain how values are getting bound to the IEnumerable during postback? How can i tweak here to post the names of the cities instead of Id's?Is there a way to get around this?
PS:I got this code from an online tutorial
You actually are setting the values for selectCities.
In your view, you have the following form:
#using (#Html.BeginForm())
{
#Html.ListBoxFor(x => x.SelectedCities, Model.Cities, new {
size=#Model.Cities.Count()})
<br/>
<input type="submit" value="submit" />
}
Here, you're using the following line to generate the listbox:
#Html.ListBoxFor(x => x.SelectedCities, Model.Cities, new { size=#Model.Cities.Count()})
Take a look at the documentation for this function. This is how you're "inserting" the selected cities when you click the button.
Essentially, you are supplying the following to the function:
x => x.SelectedCities --> The cities that are selected in the listbox by default from your viewModel AND the Selectedcities that will be posted to the POST Index method of your controller when you submit the form.
Model.Cities --> All of the available options in the listbox from your viewModel.
new { size=#Model.Cities.Count()} --> Setting the HTML Attribute size.
Because you're using a form, whenever you click the "submit" button, the client sends IEnumerable<string> SelectedCities to your POST method, Index. This is how your controller is receiving the selected values and then outputting that text.
Hopefully that helps. I can try to clarify further if needed. I suggest reading the documentation for that function, and the BeginForm() function to get some more insight.
EDIT: I realized you were also asking how to set the selectedCities list. You would set this list the same way as you set your Cities member of your ViewModel in your GET Index method on your controller:
vmc.Cities = listSelecteditem;
You would just need to generate another list of models that represents the cities you want selected. How you implement that function is, of course, up to you.
For example:
[HttpGet]
public ActionResult Index()
{
EmployeeDbContext db = new EmployeeDbContext();
List<SelectListItem> listSelecteditem = new List<SelectListItem>();
foreach (tblCity city in db.tblCities)
{
SelectListItem selectListItem = new SelectListItem()
{
Text = city.Name,
// Tweaked to use Name instead of ID in post.
Value = city.Name,
Selected = city.IsSelected
};
listSelecteditem.Add(selectListItem);
}
viewmodelCities vmc = new viewmodelCities();
// Simply set your SelectedCities here, and it will be reflected on your page.
vmc.SelectedCities = SomeService.GetSomeCities(someFilter);
vmc.Cities = listSelecteditem;
return View(vmc);
}
where SomeService.GetSomeCities is a function I made up that would return IEnumerable<String> of City IDs. I also changed the initialization of the select list to use name as it's value instead of ID.
For a listbox control, the selected values are going to be posted. If you would like the city names instead of the IDs, you can set Value = city.Name when you are populating the SelectList.
foreach (tblCity city in db.tblCities)
{
SelectListItem selectListItem = new SelectListItem()
{
Text = city.Name,
Value = city.Name, // <-- change to this
Selected = city.IsSelected
};
listSelecteditem.Add(selectListItem);
}
Also, if you're interested in code golf, you can use LINQ's Select() extension to project your dbtblCities into a List<SelectListItem> without using a loop explicitly:
var listSelecteditem = db.tblCities.Select(x => new SelectListItem {
Text = city.Name,
Value = city.Name,
Selected = city.IsSelected }).ToList();
I am merely trying to get items into an Html.DropDownList() as follows. I've debugged and know the data is coming across to the View but the dropdownlist is not displayed. Anyone know where I'm going wrong here?
#model List<ControlNumberViewer.Models.Table>
#{
Layout = null;
}
Control Number Viewer
<div id="PickTable">
#{Html.DropDownList("TableName", Model.Select(x => new SelectListItem
{
Text = x.TableName,
Value = x.TableName
}));
}
</div>
Pull your data into the controller and store it in a ViewBag. Then use DropDownListFor for strongly typed access to the data for the property TableName.
in your controller:
var linqQuery = _db.SQLTable.Select(x => new { Text = x.TableName, Value = x.TableName });
ViewBag.ListValues = new SelectList(linqQuery, "Value", "Text");
in your view:
#Html.DropDownListFor(m => m.TableName, ViewBag.ListValues as SelectList);
#{
var listitem = Model.Select(x => new SelectListItem {
Text = x.TableName,
Value = x.TableName
});
Html.DropDownList("TableName", (SelectList)listitem);
}
I have an action that retrieves data and sends it to a view. In a view I have two dropdown menus.
First drop down shows salutation (such as "Mr.", "Ms.", etc.) and does not select value I sent for some reason. The other dropdown shows language list and correctly selects value I sent to the view. The relevant code in view is shown below.
#Html.DropDownListFor(model => model.Salutation, ViewBag.salutation as IEnumerable<SelectListItem>)
#Html.DropDownListFor(model => model.Language, ViewBag.languages as IEnumerable<SelectListItem>)
In the controller I have the following code to get the dropdown data.
ViewBag.salutation = new List<SelectListItem>() {
new SelectListItem() { Text = "", Value = "" },
new SelectListItem() { Text = "Mr.", Value = "Mr." },
new SelectListItem() { Text = "Ms.", Value = "Ms." },
new SelectListItem() { Text = "Mrs.", Value = "Mrs." }
};
and
var languages = (from l in db.Languages.ToList()
select new SelectListItem()
{
Text = l.Language,
Value = l.LanguageId.ToString()
}).ToList();
languages.Insert(0, new SelectListItem() { Text = "", Value = "" });
ViewBag.languages = languages;
The only difference I could think of is that the languages dropdown has an integer as value, whereas salutation dropdown has text as value. Is this why the salutation dropdown doesn't work? I know I could go through each salutation List<SelectListItem> item and set Selected property based on the value I retrieved from database. But I was hoping there would be a cleaner way to do this.
Any ideas?
Thanks
UPDATE
I decided to do what I did for another project.
IList<SelectListItem> _salutation = new List<SelectListItem>()
{
new SelectListItem() { Value = "", Text = "" },
new SelectListItem() { Value = "Mr.", Text = "Mr." },
new SelectListItem() { Value = "Ms.", Text = "Ms." },
new SelectListItem() { Value = "Mrs.", Text = "Mrs." }
};
// I could put the following in the declaration above, but for testing purposes it's in foreach loop.
foreach (var item in _salutation)
{
// compare to what's retrieved from database
item.Selected = item.Value == _viewData.Salutation;
}
ViewBag.salutation = _salutation;
After foreach loop I output .Value, .Selected property of each item in _salutation and I get all the correct values with one item being selected. Inside the view I did the following.
#foreach (var item in ViewBag.salutation as IEnumerable<SelectListItem>)
{
<b>#item.Value : #item.Text : #item.Selected</b><br />
}
All the correct Text/Values come up but none are Selected! This happens if I output the values after I execute #Html.DropDownListFor(). If I output the ViewBag.salutation before the html helper the correct value is selected.
SOLUTION
I found the following article useful: DropDownListFor with ASP.NET MVC.
Instead of using ViewBag I added the following to the ViewModel. (Showing the part for salutations drop down.)
public class TheViewModel
{
private IList<string> _salutations = new List<string>() { "", "Mr.", "Ms.", "Mrs." };
public IEnumerable<SelectListItem> SalutationItems
{
get
{
var salutations = _salutations.Select(s => new SelectListItem { Value = s, Text= s });
return salutations;
}
}
// The rest of the ViewModel
}
And in the View I have the following.
#Html.DropDownListFor(model => model.Salutation, Model.SalutationItems)
Instead of just supplying the list to the DropDownListFor helper you could provide it a SelectList. The SelectList constructor takes the list and allows you to explicitly set the selected value as well as an overload that lets you specify the Text and Value fields.
#Html.DropDownListFor(model => model.Salutation,
new SelectList(ViewBag.salutation as IEnumerable<SelectListItem>,
"Value", "Text", Model.Salutation))
Try this,
#Html.DropDownListFor(m =>m.DDCountryModel,IEnumerable<SelectListItem>)ViewBag.salutation)
#Html.DropDownListFor(model => model.Language, IEnumerable<SelectListItem>)ViewBag.languages)
Your Model should be like this,
public class Model
{
public IEnumerable<SelectListItem> DDCountryModel{ get; set; }
public IEnumerable<SelectListItem> Language{ get; set; }
}
I have a Razor page with a drop down list inside a form:
#using (Html.BeginForm("ProductsByOwners", "Report", FormMethod.Post, new { #id = "ProductsByOwners" }))
{
#Html.Label("Choose product owner: ")
#Html.DropDownList("OwnerList", (SelectList)ViewBag.OwnerList, new { #onchange = "this.form.submit();" })
}
The selected value of my SelectList is not being carried over to the DropDownList. I've debugged and stepped through the code and found that (SelectList)ViewBag.OwnerList evaluates properly and has the expected value selected, but the resulting HTML does not have any of the option tags selected.
Can anyone see what I'm doing wrong here?
UPDATED
Here is how the SelectList is created in my action:
ViewBag.OwnerList = new SelectList(ListUtils.ProductOwners(), "Key", "Value", values["OwnerList"]);
The result has the value indicated by values["OwnerList"] selected.
Thanks!
You are not using the DropDownList helper properly. In order to create a dropdownlist you need 2 things:
a scalar property to bind to the selected value when the form is submitted
a collection to bind the options to
In your example you have only one of those 2 things (the second). Your first argument is called OwnerList and you have ViewBag.OwnerList passed as second argument.
So:
#Html.DropDownList(
"SelectedOwnerId",
(SelectList)ViewBag.OwnerList,
new { #onchange = "this.form.submit();" }
)
Obviously I would recommend you using strongly typed views ans view models. And obviously get rid of the weakly typed ViewBag/ViewData/ViewCrap.
So start by designing a view model to meet the requirements of your view (which from what you have shown so far is to display a dropdownlist):
public class OwnerViewModel
{
[DisplayName("Choose product owner: ")]
public string SelectedOwnerId { get; set; }
public IEnumerable<SelectListItem> OwnerList { get; set; }
}
then a controller:
public class ReportController: Controller
{
public ActionResult ProductsByOwners()
{
var model = new OwnerViewModel
{
// preselect the second owner
SelectedOwnerId = "2",
// obviously those come from your database or something
OwnerList = new[]
{
new SelectListItem { Value = "1", Text = "owner 1" },
new SelectListItem { Value = "2", Text = "owner 2" },
new SelectListItem { Value = "3", Text = "owner 3" },
}
};
return View(model);
}
[HttpPost]
public ActionResult ProductsByOwners(OwnerViewModel model)
{
...
}
}
and you have a corresponding strongly typed view:
#model OwnerViewModel
#using (Html.BeginForm("ProductsByOwners", "Report", FormMethod.Post, new { id = "ProductsByOwners" }))
{
#Html.LabelFor(x => x.SelectedOwnerId)
#Html.DropDownListFor(
x => x.SelectedOwnerId,
Model.OwnerList,
new { onchange = "this.form.submit();" }
)
}
The most common reason the selected item is not selected in the DDL is you've named the selectlist the same as the model.
Strongly typed views are preferred, but it's fine to pass the SelectList in a Viewbag. See my tutorial Working with the DropDownList Box and jQuery and my blog Cascading DropDownList in ASP.Net MVC
I am using a dropdown list as follows.
<%=Html.DropDownList("ddl", ViewData["Available"] as SelectList,
new { CssClass = "input-config", onchange = "this.form.submit();" })%>
On its selection change I am invoking post action. After the post the same page is shown on which this drop down is present. I want to know about the HTML attribute for the drop down which will let me preserve the list selection change. But as of now the list shows its first element after the post.
e.g. The dropdoen contains elements like 1,2,3,etc. By default 1 is selected. If I select 2, the post is invoked and the same page is shown again but my selection 2 goes and 1 is selected again.
How can preserve the selection?
Thanks,
Kapil
You have to make the list of select list items again and tell which of the items is the selected one in every post (Selected property of the SelectListItem).
When you perform the post you will be setting the ViewData["Available"] again, you can set the select item here. So when you create the drop down list in the html the selected item is already selected. So your code could look something like:
ViewData["Available"] = new SelectList( items, "dataValueField", "dataTextField", "selectedValue" );
You have to take the property model ddl, or receive it as a parameter in the action, such as:
public ActionResult Action(Model model, string ddl)
Then to create ViewData [" Available "], you have to pass it as selected value
public ActionResult Action(Model model, string ddl)
{
ViewData["Available"] = List<SelectListItem>
{
new SelectListItem { Text = "1", Value = "1", Selected = (ddl == "1") },
new SelectListItem { Text = "2", Value = "2", Selected = (ddl == "2") },
new SelectListItem { Text = "3", Value = "3", Selected = (ddl == "3") }
};
return View(model);
}
OR:
public ActionResult Action(Model model, string ddl)
{
var list = List<SelectListItem>
{
new SelectListItem { Text = "1", Value = "1" },
new SelectListItem { Text = "2", Value = "2" },
new SelectListItem { Text = "3", Value = "3" }
};
ViewData["ddl"] = new SelectList(list, "value", "text", ddl);
return View(model);
}
EDIT: See also this
This worked for me:
<%=Html.DropDownList("Ibus", ViewData["Ibus"] as SelectList, new { **#class** = "dASDropDown" })%>