Selected value not set on DropDownListFor() in MVC4 - c#

It seems like this question has been asked too many times. But this is driving me nuts.
This is my (simplified) model.
public class UserEditModel
{
[Required]
public string Title { get; set; }
private IEnumerable<SelectListItem> _titleList;
public IEnumerable<SelectListItem> TitleList
{
get { return _titleList.Select(x => new SelectListItem {
Selected = (x.Value == Title),
Text = x.Text,
Value = x.Value
});
}
set { _titleList = value; }
}
}
The Text and Value properties of each SelectListItem in the TitleList member are identical. For example:
new SelectListItem { Text = "Mr", Value = "Mr" }
When the following code is posted, the correct Title value is bound to the model, but whenever the model is pushed to the view in response to a POST or a GET, the selected value is not set on the dropdownlist, even though all the intellisense shows that the correct values are present.
#Html.DropDownListFor(x => x.Title, Model.TitleList)
I have ensured that the code is correct based on several articles and several SO answers, so I am stumped.
Any suggestions?
Update:
For completeness, this is the action and supporting method:
[HttpGet]
public ActionResult Edit(int id)
{
var user = _userService.Get(id);
var model = new UserEditModel()
{
...
Title = user.Title,
TitleList = ListTitles()
};
return View(model);
}
private IEnumerable<SelectListItem> ListTitles()
{
var items = new[] {
new SelectListItem() {Text = "Mr", Value = "Mr" },
new SelectListItem() {Text = "Mrs", Value = "Mrs"},
new SelectListItem() {Text = "Ms", Value = "Ms"},
new SelectListItem() {Text = "Miss", Value = "Miss"},
new SelectListItem() {Text = "Professor", Value = "Professor"},
new SelectListItem() {Text = "Dr", Value = "Dr" }
};
return items;
}
As you see there is nothing fancy, just a straightforward implementation.

You need to add ModelState.Clear() because by default when returning a view from a post action, it thinks it has failed validation, so uses the values in ModelState and not the values in the Model. Many people think this is actually a bug in MVC, but it's by design:
ASP.NET MVC assumes that if you’re rendering a View in response to a HttpPost, and you’re using the Html Helpers, then you are most likely to be redisplaying a form that has failed validation. Therefore, the Html Helpers actually check in ModelState for the value to display in a field before they look in the Model. This enables them to redisplay erroneous data that was entered by the user, and a matching error message if needed.
Link

Well, it seems there is actually nothing wrong with the code, just the name of the Title property in the model.
It looks like Title is a reserved word and replacing it with TitleX or more appropriately Salutation makes everything work fine.

Are you sure you retrieve the selectlist item appropriately in the controller?
For me it is working fine.
I would use a get method instead of a property ( GetTitleList(string value) ), to avoid mistakes in getting the selectionlist farther along in your code.

Related

ASP.NET MVC get value from DropDownList() usingn FormCollection

I have a simple drop down list in Razor syntax:
#{
List<SelectListItem> listItems = new List<SelectListItem>();
listItems.Add(new SelectListItem { Text = "1 kg", Value = "1" });
listItems.Add(new SelectListItem { Text = "2 kg", Value = "2" });
listItems.Add(new SelectListItem { Text = "3 kg", Value = "3" });
listItems.Add(new SelectListItem { Text = "4 kg", Value = "4" });
listItems.Add(new SelectListItem { Text = "5 kg", Value = "5" });
}
#Html.DropDownList("Weight", (IEnumerable<SelectListItem>)listItems, new { #class = "form-control" })
#Html.Hidden("Weight", 0)
I also have a Controller action which gets the data from the form via FormCollection defined as:
[HttpPost]
public ActionResult AddProductsToCart(FormCollection collection /*int ?Id*/)
{
MyDBContext myDBContext = new MyDBContext();
var value = collection["Weight"];
}
But here I'm not able to get value of selected index in the Drop Down List in the collection upon submitting the form. Instead, I get 1, 1, 1 as the only single key in collection.
Any idea would be appreciated. :)
As I tried your code in ASP.NET MVC 4 application,
The HTML is having two same Id for two HTML controls as:
#Html.DropDownList("Weight", (IEnumerable<SelectListItem>)listItems, new { #class = "form-control" })
#Html.Hidden("Weight", 0)
So when you access the data from FormCollection class it finds the two Id on the HTML so it separates each control value by Comma , like [Not sure why]:
So If you want only one value from View for that particular control you can use one variable which is the same name as control name in the method like:
[HttpPost]
public ActionResult AddProductsToCart(/*Might be no need of this*/ FormCollection fc, string Weight)
{
var selectedValue = Weight;
return View();
}
thanks all for your kind response.
FormCollection was returning the values of all the dropdowns which was in view.

How to keep the selected value from the dropdown when the page is changed?

I am working on a project in C# (using mvc) and I had to make a dropdown filter in my view with only two choices: Yes and No.
Here is the code that populates the dropdown:
Service method:
public List<SelectListItem> cancelledForDp()
{
List<SelectListItem> cancelled = new List<SelectListItem>();
var data = new[]
{
new SelectListItem { Value = "1",Text = "Yes" },
new SelectListItem { Value = "NULL",Text = "No" }
};
cancelled = data.ToList();
return cancelled;
}
Controller:
ViewBag.cancelledDp = utilService.cancelledForDp();
View:
#Html.DropDownList("cancelled", (IEnumerable<SelectListItem>)ViewBag.cancelledDp, new { id = "chosenCancelled" })
The values in the column in the database table are: "1" and NULL (I mean the values connected with the filter). My filter works correctly.
When I filter with the value No, a few pages are returned. When I go to a different page than the first (2 or more), the value of the dropdown is not kept. It should be No, but instead it is Yes.
I searched for answers connected with my problem here, but did not find anything appropriate.
I guessed the problem is connected with NULL value so I tried this:
In the service:
public List<SelectListItem> cancelledForDp()
{
List<SelectListItem> cancelled = new List<SelectListItem>();
var data = new[]
{
new SelectListItem { Value = "1",Text = "Yes" },
new SelectListItem { Value = "2",Text = "No" }
};
cancelled = data.ToList();
return cancelled;
}
Controller:
if(cancelled == 2)
{
cancelled = null;
}
But I got the same results. When I selected No in the filter and went to the second page, Yes was in the dropdown instead of No.
I debugged and found that the value of the parameter cancelled of the method in the controller is null when I went to the second page.
How to keep the selected value from the dropdown when the page is changed?
Your code is generating <option> elements with values of "1" and "NULL". The text "NULL" is not the same as null value (which is recognized by an empty string - i.e. it has no value). If the value of property cancelled is null then the first option will be selected because there is no option element with an empty value (and because something has to be selected)
In order for it to be selected, your element needs to be <option value="">No</option> which you can generate using either
public IEnumerable<SelectListItem> cancelledForDp()
{
return new List<SelectListItem>()
{
new SelectListItem { Value = "1",Text = "Yes" },
new SelectListItem { Value = "",Text = "No" }
};
}
or
public IEnumerable<SelectListItem> cancelledForDp()
{
return new List<SelectListItem>()
{
new SelectListItem { Value = "1", Text = "Yes" },
};
}
and in the view use
#Html.DropDownList("cancelled", (IEnumerable<SelectListItem>)ViewBag.cancelledDp, "No", new { id = "chosenCancelled" })
where the 3rd parameter creates the labelOption with a null value.
As a side note, if your field can only store 2 values, then you should be using as database BIT field so that the property is
public bool IsCancelled { get; set; }
not int? cancelled (or is it string cancelled?)
and simply use
#Html.CheckBoxFor(m => m.IsCancelled)
in the view. I also recommend you always use the strongly typed ***For() methods.

C# MVC Dropdownlist no ViewData item

I am having an issue with a dropdownlist I have in a PartialView.
Basically get the following error
There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'Status'.
Here is my ActionResult method inside the controller
[HttpGet]
public ActionResult Status()
{
List<SelectListItem> Status = new List<SelectListItem>();
Status.Add(new SelectListItem { Text = "Open", Value = "1" });
Status.Add(new SelectListItem { Text = "Closed", Value = "2" });
Status.Add(new SelectListItem { Text = "Delete", Value = "3" });
ViewData["Status"] = Status;
return View();
}
My Status Partial View where I call the select list
#Html.DropDownList("Status", ViewData["Status"] as SelectList)
And then I call the partial view from my main view as follows
#Html.Partial("Status")
I am just not sure why its giving the above error. I took at look at this asp.net mvc dropdownlist no ViewData item and still not able to rectify the issue?
Update
As per #MikeDebela solution my Status Action Item was never been called. So used the following syntax to call the Action directly
#{Html.RenderAction("Status");}
When you use Partial helper, the runtime looks for the view and renders a string (your action will never get executed). On the other hand, RenderAction executes the action and displays the result. So, use:
#{Html.RenderAction("Status");}
#Html.DropDownList("Status", new SelectList((System.Collections.IEnumerable) ViewData["Status"],"Text","Value"))
you can use this line to fill dropdownlist with ViewData
Please check that the code as follows because it is working with me
public ActionResult Index()
{
List<SelectListItem> Status = new List<SelectListItem>();
Status.Add(new SelectListItem { Text = "Open", Value = "1" });
Status.Add(new SelectListItem { Text = "Closed", Value = "2" });
Status.Add(new SelectListItem { Text = "Delete", Value = "3" });
ViewData["Status"] = Status;
return View();
}
#Html.DropDownList("Status", new SelectList((System.Collections.IEnumerable)ViewData["Status"], "Value", "Text"))
or you can use
#Html.DropDownList("Status", (IEnumerable<SelectListItem>)ViewData["Status"])

ASP.Net MVC 5 Selecting muliple items in a listbox on load

Wrapping my head around MVC.
I have a list of items. I need to load the screen with some of these selected by default.
Loading the items is one thing, trying to select some by default isn't working for me.
Any idea where I am going wrong?
I know there are many answers to a similar question, though I can't seem to translate the answers to my needs.
Here is the code I have, and tried - i am also trying to understand the various options in the html helpers. Please take this into consideration when posting a solution.
This is the most recent iteration of my code; i have gone through a bunch....
In my Controller:
public ActionResult Index()
{
ViewBag.Statuses = AddStatuses();
return View();
}
private MultiSelectList AddStatuses()
{
string[] defaultSelected = { "Ready", "Done", "Error" };
List<SelectListItem> listItems = new List<SelectListItem>();
List<Status> s = allTypes.GetStatuses();
s.ForEach(status =>
{
listItems.Add(new SelectListItem()
{
Text = status.Name,
Value = status.ID.ToString(),
Selected = true,// defaultSelected.Contains(status.Name)
});
});
return new MultiSelectList(listItems, "Value", "Text");
}
In an attempt to test my defaultSelected.Contains, i just commented it out to select ALL as true... still didn't work...
I have tried these in my view
#Html.DropDownList("Statuses", null, null, new { #class = "form-control", multiple = true, id="queueStatuses" })
#Html.ListBox("Name", ViewBag.Statuses as MultiSelectList, new { #class = "form-control", id = "queueStatuses" })
#Html.ListBox("Statuses", null, new { #class = "form-control", id = "queueStatuses" })
I a) don't understand what i am doing and b) can't get it to work... :)
I am looking for:
You can use the ListBoxFor helper method along with the user of a view model to pass the items for your list box.
So create a new view model to transfer data from your action method to view
public class CreateIssue
{
public List<SelectListItem> Statuses { set;get;}
public int[] SelectedStatuses { set;get;}
}
Now in your GET action, create an object of this, load the Statuses collection and send it to the view. If you want to preselect some items, set the SelectedStatuses property.
public ActionResult Index()
{
var vm = new CreateIssue();
//Hard coded for demo. You may replace with values coming from db table.
vm.Statuses = new List<SelectListItem> {
new SelectListItem { Value="1", Text="Ready"},
new SelectListItem { Value="2", Text="Done"},
new SelectListItem { Value="3", Text="Building"},
new SelectListItem { Value="4", Text="Error"},
};
//For preselecting items, set it here
vm.SelectedStates=new int[] { 2,3};
return View(vm);
}
and your in your view, which is strongly typed to the view model, use the ListBoxFor helper method.
#model CreateIssue
#using (Html.BeginForm())
{
<label>Select many statuses</label>
#Html.ListBoxFor(m => m.SelectedStatuses, Model.Statuses)
<input type="submit"/>
}
Thank you #Shyju. I am sure your answer works.
As mentioned in my comments though, I don't want to go through the hoops of having a view model in this instance. I was looking for a simple way to implement this.
Seems all i needed to do was change my MultiSelectList and pass in an array of selected 'value's.
This fixes my issue:
private MultiSelectList AddStatuses()
{
string[] defaultSelected = { "3", "5", "6" };
List<SelectListItem> allItems = new List<SelectListItem>();
List<Status> s = allTypes.GetStatuses();
s.ForEach(status =>
{
allItems.Add(new SelectListItem()
{
Text = status.Name,
Value = status.ID.ToString(),
});
});
return new MultiSelectList(allItems, "Value", "Text", defaultSelected);
}
And my ListBox is the same. Went with this one in the end:
#Html.ListBox("status", (IEnumerable<SelectListItem>)ViewBag.Statuses, new { #class = "form-control" })

trying to set a dropdown in MVC

I almost have this solved but need a little push.
Here's what I have:
In the database I have a field called active that is a bit field (True/False)
I have placed a dropdownlist on the View form like this:
<%= Html.DropDownList("lstActive", new SelectList((IEnumerable)ViewData["ActiveList"])) %>
In my controller, I simply have this code to generate the True/False in the dropdown:
List<string> activeList = new List<string>();
activeList.Add("True");
activeList.Add("False");
ViewData["ActiveList"] = new SelectList(activeList);
I want to bind to the field in the database called active and select it in the dropdown. When I view it like this I get this:
alt text http://rjmueller.net/sitesimages/temp/dropdown.gif
So the questions are these:
Obviously I am not pointing to the Value and Text property but what is that in this case?
And how do I select the value that is in the database?
Any help would be appreciated.
First, this is probably better suited to radio buttons, not a select. Second, you really ought to have a view model with a property that is an IEnumerable<SelectListItem> that supplies the values for the select. You can construct that directly in the model.
var model = new ViewModel();
model.ActiveList = new List<SelectListItem>
{
new SelectListItem { Text = "Yes", Value = "true" },
new SelectListITem { Text = "No", Value = "false" }
};
model.Active = false; // this will be the default
return View( model );
Then in your view (strongly-typed to your view model type):
<%= Html.DropDownListFor( m => m.Active, Model.ActiveList ) %>
Using radio buttons, you can omit the list (since there are only the two choices).
<%= Html.RadioButtonFor( m => m.Active, true ) %> Yes
<%= Html.RadioButtonFor( m => m.Active, false ) %> No
Here's a couple of suggestions for you.
First, your DropdownList's name is "lstActive", so if you create a List<SelectListItem> called "lstActive" and pass that back in ViewData, you don't have to do anything fancy with boxing. Then your declaration looks like:
<%= Html.DropDownList("lstActive") %>
easy, huh?
In your controller, you create your List. Here's a method I've used:
private List<SelectListItem> GetAccounts(User user)
{
var items = new List<SelectListItem>();
foreach (Account account in user.Accounts)
{
var item = new SelectListItem();
item.Text = account.Name;
item.Value = account.AccountId.ToString();
if (ActiveAccount == account.AccountId)
item.Selected = true;
items.Add(item);
}
return items;
}
Basically, what I'm trying to point out is that you can set a property on your SelectListItem that you wish to be displayed as selected. Here, I'm using my own code for Users and Accounts, but you'd substitute your own data based on your db query.
First thing, you're recreating a SelectList the ViewData data, you should declare the DropBox as follows:
<%= Html.DropDownList("lstActive", ViewData["ActiveList"]) %>
Second, instead of creating a generic list on the controller, create a SelectList and add SelectListItems to it:
var activeList = new SelectList
{
new SelectListItem { Text = "True", Value = true },
new SelectListItem { Text = "False", Value = false }
};
ViewData["ActiveList"] = activeList;
This should clarify:
Drop-down Lists and ASP.NET MVC
For each select list element you need to set the Text and Value properties...
One solution could be as follows:
Model:
public class NameValue
{
public string Name { get; set; }
public string Value { get; set; }
}
Controller:
string currentActiveValue = myDB.active.ToString();
List<NameValue> yesNoList = new List<NameValue>
{
new NameValue { Name = "Yes", Value = "True" },
new NameValue { Name = "No", Value = "False" }
};
SelectList myActiveList = new SelectList(yesNoList, "Name", "Value", currentActiveValue);
ViewData["ActiveList"] = myActiveList;
View:
div>Is Active: <%= Html.DropDownList("ActiveList") %></div>

Categories

Resources