SelectList selected value not carried over to DropDownList - asp.net-mvc

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

Related

Bootstrap Multiselect Get Selected values on HttpPost

I'm using this Bootstrap Multiselect and my problem is that I cant get the selected values on HttpPost on ASP.Net MVC.
Problems Encountered:
after clicking save, Only the first selected value is the present on
the model. (SOLVED)
after clicking save, Only the first selected value is the present on
the dropdownlist.
Sample.chtml:
#model SampleProject.Models.SampleViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(model => model.Selected, new SelectList(Model.List, "value", "text"), new { #class = "multiselect form-control", multiple = "multiple" })
<input type="submit" value="Save" />
}
Model:
public class SampleViewModel
{
public string[] Selected { get; set; }
public SelectList List { get; set; }
}
Controller:
public class DashboardController : Controller
{
public ActionResult Sample()
{
SampleViewModel model = new SampleViewModel();
model.List = new SelectList(new List<string>() { "1", "2", "3" });
return View(model);
}
[HttpPost]
public ActionResult Sample(SampleViewModel model)
{
model.List = new SelectList(new List<string>() { "1", "2", "3" });
return View(model);
}
}
Selection:
I cant get the selected values correctly on HttpPost
Code Behind/HttpPost: (Wrong)
After HttpPost: (Correct)
A <select multiple="multiple"> posts back an array of values (not a single value). You property Selected needs to be IEnumerable, for example
public string[] Selected { get; set; }
Side note: Since the text and value properties are the same, you can simplify you code by making the List property SelectList
public SelectList List { get; set; }
and then in the controller
model.List = new SelectList(new List<string>() { "1", "2", "3" })
(although its not clear why you would not use int)
Didn't see this answer anywhere, so to solve the issue with having only 1 item selected after the post back you need to use:
#Html.ListBoxFor(..
instead of #Html.DropDownListFor

How to work with DropDownListFor in an EDIT view

Hi I have a problem with DropDownListFor on the Edit view.
Basically I'm using a partial view which contains my form and in my Edit and Create view I call this partial view.
I have around 5 similiar DropdownlistFor and these work well on create action but in edit doesn't, mainly i'm not getting (unable) to set the selected value.
In my Edit Action (GET), I fill my property ViewModel if the true object has the property filled.
if(icb.BAOfficer != null)
editICB.BAOfficer = icb.BAOfficer;
List<Staff> staffs = _fireService.GetAllStaffs().ToList();
staffs.Insert(0, new Staff { StaffId = -1, Name = "" });
editICB.BAOfficers = staffs;
return View(editICB);
This is how I'm filling my drop down and how I'm trying to set the selected value.
#Html.DropDownListFor(model => model.BAOfficerSelected, new SelectList(Model.BAOfficers, "StaffId", "Name", (Model.BAOfficer!= null ? Model.BAOfficer.StaffId:-1)), new { #class = "rounded indent" })
#Html.ValidationMessageFor(model => model.BAOfficer.StaffId)
I solve the problem setting a value to my model.BAOfficerSelected in Edit Action, this was the (easy) secret.
I need the first item like a empty option because is not a required information, but on the edit view if has value I need to set it as selected option.
In the end, it was my code.
My Model
public int BAOfficerSelected { get; set; }
public SelectList BAOfficers { get; set; }`
My Controller Create/Edit Action
if (icb.BAOfficer != null) // only for edit action
editICB.BAOfficerSelected = icb.BAOfficer.StaffId; //this will set the selected value like a mapping
//for Edit and Create
List<Staff> staffs = _fireService.GetAllStaffs().ToList();
staffs.Insert(0, new Staff { StaffId = -1, Name = "" });
editICB.BAOfficers = new SelectList(staffs, "StaffId", "Name");
return View(editICB);`
My View
#Html.DropDownListFor(model => model.BAOfficerSelected, Model.BAOfficers, new { #class = "rounded indent" })
I hope this can help others.
The best and cleanest way of doing this is setting the selected value in server side, in the SelectList object.
So, if your BAOfficerSelected is nullable... it is all simpler: You don't need to rely in adding a dummy item to hold the -1 for not selected value.
Instead, you do it this way:
List<Staff> staffs = _fireService.GetAllStaffs().ToList();
editICB.BAOfficers = new SelectList(staffs, "StaffId", "Name", editICB.BAOfficer != null ? editICB.BAOfficer.StaffId : null);
Of course, the BAOfficers need to be changed type from List<Staff> to SelectList.
Then, in your partial view you do:
#Html.DropDownListFor(model => model.BAOfficerSelected, Model.BAOfficers, "Select one...", new { #class = "rounded indent" })
Adding the 3rd parameter is needed to indicate that the default value (if nothing is selected) is that text.
Instead of using a SelectList, I often find it works better to use a List<SelectListItem>.
Further, I usually use an EditorTemplate for my dropdowns to keep my views clean.
So if my select list returns List<SelectListItem>:
public List<SelectListItem> BAOfficers { get; set };
You can set it up like this:
model.BAOfficers = staffs.Select(staff =>
new SelectListItem { Text = staff.Name, Value = staff.StaffId }).ToList();
Then in your EditorTemplate:
<!-- EditorTempaltes\DropDownList.cshtml -->
#model System.String
<p>
#Html.LabelFor(m => m):
#Html.DropDownListFor(m => m, new SelectList(
(List<SelectListItem>)ViewData["selectList"], "Value", "Text",
String.IsNullOrEmpty(Model) ? String.Empty : Model), String.Empty)
#Html.ValidationMessageFor(m => m)
</p>
And then in the view, just pass the SelectList into the EditorTemplate:
#Html.EditorFor(m => m.BAOfficerSelected, "DropDownList",
new { selectList = Model.BAOfficers() })
I met the same problem ,too.
According the article https://dotnetfiddle.net/PIGNLF which way gave a simple way to deal with this problem without two Models or more classes.enter link description here
here is my code
add model
public class NoteSelectLisModel
{
public string Value { get; set; }
public string Name { get; set; }
}
add Controller
public ActionResult Edit(int? _ID)
{
ViewBag.NoteState = new SelectList(new List<NoteSelectLisModel>()
{
new NoteSelectLisModel() {Value="1",Name="A)"},
new NoteSelectLisModel() {Value="2",Name="B"},
new NoteSelectLisModel() {Value ="3",Name ="C"}
}, "Value", "Name", 1);
Table ut = _db.Tables.Find(_ID);
if (ut == null)
{
return HttpNotFound();
}
else
{
return View(ut);
}
}
add View .cshtml
#Html.DropDownListFor(m => m.NOTE, (IEnumerable<SelectListItem>)ViewBag.NoteState, "No Selected")
The edit's Model is the same and the dropdownlist passed by View.bag

Creating DropDownListFor in a Partial View in MVC

I have created a partial view that displays a dropdownlist
html.DropDownListFor(m => m.SelectOption, Model.SelectOption)
I get an error of Object not reference to an instance....
If I put the code above into my view (aspx) it works fine no problem. But in the partial view I get the error.
The textbox controls in my partial view works fine using the same model. I just can't around the DropDownList.
You haven't actually shown how you are calling the partial view and whether your controller action has actually passed a model to this view.
Make sure that your controller has properly initialized the model. So if we suppose that you have the following model:
public class MyViewModel
{
public string SelectedOption { get; set; }
public IEnumerable<SelectListItem> SelectOptions { get; set; }
}
and the following controller action:
public ActionResult Foo()
{
var model = new MyViewModel();
model.SelectOptions = new[]
{
new SelectListItem { Value = "1", Text = "item 1" },
new SelectListItem { Value = "2", Text = "item 2" },
new SelectListItem { Value = "3", Text = "item 3" },
};
return View(model);
}
ten you could have a corresponding view which will call a partial:
#model MyViewModel
#Html.Partial("_MyPartial", Model)
and the _MyPartial.cshtml:
#model MyViewModel
#Html.DropDownListFor(x => x.SelectedOption, Model.SelectOptionOptions)
Notice how you need 2 properties on your view model in order to create a dropdown list => a scalar property (SelectedOption) that will be used to bind the selected value and a collection property that will contain the list of values you would like to display in the dropdown (SelectOptionOptions).
In your code you are using the same property for both which is wrong:
#Html.DropDownListFor(m => m.SelectOption, Model.SelectOption)

How does Model binding with a selectlist work?

I'm having problems retrieving the values of a selectlist in my form collection. I've tried making a viewmodel with an attribute with the same name as the select list.
I'm honestly just realizing I REALLY don't understand how model binding works with selectlists. I've just been assuming that the following conventions apply:
Name the select list the same thing as the attribute on the model you want it to bind to.
Apart from that, I really don't get it. I've looked at several books on it and they're useless frankly.
How does a select list work with a) form collection and b) a particular model?
Here's an example:
Model:
public class MyViewModel
{
public string SelectedItemValue { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
}
Controller:
public class HomeController: Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
// TODO: Fetch those from a repository
Items = new SelectList(
new[]
{
new SelectListItem { Value = "1", Text = "Item 1" },
new SelectListItem { Value = "2", Text = "Item 2" },
new SelectListItem { Value = "3", Text = "Item 3" },
},
"Value",
"Text"
)
};
}
[HttpPost]
public ActionResult Index(string selectedItemValue)
{
// Here you get the selected value from the dropdown
return ...
}
}
View:
<% using (Html.BeginForm()) { %>
<%= Html.DropDownListFor(x => x.SelectedItemValue, Model.Items)
<input type="submit" value="OK" />
<% } %>

Challenges with selecting values in ListBoxFor

Working on my first ASP.Net MVC2 web app recently, I came across some issues when I needed to select multiple values in a list box. I worked around it with some jQuery, but went ahead and put together some very simple code to demonstrate. I'm using EF for the model, with two entities - Customers and HelpDeskCalls:
Controller:
public ActionResult Edit(int id)
{
Customer currCustomer = ctx.Customers.Include("HelpDeskCalls").Where(c => c.ID == id).FirstOrDefault();
List<HelpDeskCall> currCustCalls = (ctx.HelpDeskCalls.Where(h => h.CustomerID == id)).ToList();
List<SelectListItem> currSelectItems = new List<SelectListItem>();
List<String> selectedValues = new List<string>();
foreach (HelpDeskCall currCall in currCustCalls)
{
bool isSelected = (currCall.ID % 2 == 0) ? true : false;
//Just select the IDs which are even numbers...
currSelectItems.Add(new SelectListItem() { Selected = isSelected, Text = currCall.CallTitle, Value = currCall.ID.ToString() });
//add the selected values into a separate list as well...
if (isSelected)
{
selectedValues.Add(currCall.ID.ToString());
}
}
ViewData["currCalls"] = (IEnumerable<SelectListItem>) currSelectItems;
ViewData["currSelected"] = (IEnumerable<String>) selectedValues;
return View("Edit", currCustomer);
}
View:
<div class="editor-field">
<%: Html.ListBoxFor(model => model.HelpDeskCalls, new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable) ViewData["currSelected"]), new { size = "12" })%>
<%: Html.ListBoxFor(model => model.HelpDeskCalls, ViewData["currCalls"] as IEnumerable<SelectListItem>, new { size = "12"}) %>
<%: Html.ListBox("Model.HelpDeskCalls", new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable)ViewData["currSelected"]), new { size = "12"}) %>
<%: Html.ValidationMessageFor(model => model.HelpDeskCalls) %>
</div>
For this sample, I'm just selecting HelpDeskCall.IDs which are even. I'm trying two different syntaxes for ListBoxFor: One uses an IEnumerable of values for selections, one using an IEnumerable of SelectListItems. By default, when I run this code, no selections are made to either ListBoxFor, but the non-strongly typed ListBox selects correctly.
I read this post on ASP.Net and this thread on SO, but no joy. In fact, if I add the override ToString() to my HelpDeskCall class (as suggested in the ASP.net thread) all values are selected, which isn't right either.
If someone could shed some light on how this should work (and what I'm missing or doing wrong), this then neophyte would be very grateful.
Here's an example illustrating the strongly typed version:
Model:
public class MyViewModel
{
public int[] SelectedItemIds { get; set; }
public MultiSelectList Items { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
// Preselect items with id 1 and 3
var selectedItemIds = new[] { 1, 3 };
var model = new MyViewModel
{
Items = new MultiSelectList(
new[]
{
// TODO: Fetch from your repository
new { Id = 1, Name = "item 1" },
new { Id = 2, Name = "item 2" },
new { Id = 3, Name = "item 3" },
},
"Id",
"Name",
selectedItemIds
)
};
return View(model);
}
}
View:
<%: Html.ListBoxFor(x => x.SelectedItemIds, Model.Items) %>
I don't know if this behaviour has changed in the RTM of MVC3 that I'm using, but it seems that selection and binding now works out of the box. The only catch is that the model should contain a property with the IDs, like that :
public class MyViewModel {
public int[] ItemIDs { get; set; }
}
Then the following in the view would work fine, both pre-selecting the correct values and binding correctly during post:
#Html.ListBoxFor(model => model.ItemIDs, (IEnumerable<SelectListItem>)(new[] {
new SelectListItem() { Value = "1", Text = "1" },
new SelectListItem() { Value = "2", Text = "2" }
}))
I have found better workaround. Usual way to preselect select list:
#Html.ListBoxFor(
model => model.Roles,
new MultiSelectList(db.Roles, "Id", "Name")
)
#Html.ValidationMessageFor(model => model.Roles)
Doesn't work.., never ever any option is selected, until:
public ActionResult Edit(int id)
{
var user = db.Users.Find(id);
// this is workaround for http://aspnet.codeplex.com/workitem/4932?ProjectName=aspnet
ViewData["Roles"] = user.Roles.Select(r => r.Id);
return View(user);
}
Selected Roles has to be stored in ViewData, to workaround nasty bug.
Another option is to take advantage of nameof, you could do something like this;
Html.ListBox(nameof(MainProjectViewModel.Projects), Model.Projects)

Resources