Debugging I get this:
So, User_SportsList is a MultiSelectList with the proper Items and the proper SelectedValues.
I pass to the view like this:
ViewBag.usl = User_SportsList;
In my View I have this:
#Html.ListBox("UserSports", ViewBag.usl as MultiSelectList)
And is showing the list with all the items, but SelectedValues aren't working. What I'm doing wrong ?
The SelectedValues property needs to contain an array of values (where "value" is defined by DataValueField), and not the items themselves. So, in this example, you should set SelectedValues equal to:
User_SportsList.SelectedValues = new [] { 3, 4 };
Related
My model contains an array of zip code items (IEnumerable<SelectListItem>).
It also contains an array of selected zip codes (string[]).
In my HTML page, I want to render each selected zip code as a drop down with all the zip code options. My first attempt did not work:
#foreach (var zip in Model.ZipCodes) {
Html.DropDownList( "ZipCodes", Model.ZipCodeOptions )
}
I realized that although that would produce drop downs with the right "name" attribute, it wouldn't know which element of ZipCodes holds the value for that particular box, and might just default to the first one.
My second attempt is what really surprised me. I explicitly set the proper SelectListItem's Selected property to true, and it still rendered a control with nothing selected:
#foreach (var zip in Model.ZipCodes) {
Html.DropDownList( "ZipCodes", Model.ZipCodeOptions.Select( x => (x.Value == zip) ? new SelectListItem() { Value = x.Value, Text = x.Text, Selected = true } : x ) )
}
There, it's returning a new IEnumerable<SelectListitem> that contains all the original items, unless it's the selected item, in which case that element is a new SelectListItem with it's Selected property set to true. That property is not honored at all in the final output.
My last attempt was to try to use an explicit index on the string element I wanted to use as the value:
#{int zipCodeIndex = 0;}
#foreach (var zip in Model.ZipCodes) {
Html.DropDownList( "ZipCodes[" + (zipCodeIndex++) + "]", Model.ZipCodeOptions )
}
That doesn't work either, and probably because the name is no longer "ZipCodes", but "ZipCodes[x]". I also received some kind of read-only-collection error at first and had to change the type of the ZipCodes property from string[] to List<string>.
In a forth attempt, I tried the following:
#for (int zipCodeIndex = 0; zipCodeIndex < Model.ZipCodes.Count; zipCodeIndex++)
{
var zip = Model.ZipCodes[zipCodeIndex];
Html.DropDownListFor( x => x.ZipCodes[zipCodeIndex], Model.ZipCodeOptions )
}
That produces controls with id like "ZipCodes_1_" and names like "ZipCodes[1]", but does not select the right values. If I explicitly set the Selected property of the right item, then this works:
#for (int zipCodeIndex = 0; zipCodeIndex < Model.ZipCodes.Count; zipCodeIndex++)
{
var zip = Model.ZipCodes[zipCodeIndex];
Html.DropDownListFor( x => x.ZipCodes[zipCodeIndex], Model.ZipCodeOptions.Select( x => (x.Value == zip) ? new SelectListItem() { Value = x.Value, Text = x.Text, Selected = true } : x ) )
}
However, the problem with that approach is that if I add a new drop downs in JavaScript and give them all the name "ZipCodes", then those completely override all the explicitly indexed ones, which never make it to the server. It doesn't seem to like mixing the plain "ZipCodes" name with explicit array elements "ZipCodes[1]", even though they map to the same variable when either is used exclusively.
In the U.I., user's can click a button to add a new drop down and pick another zip code. They're all named ZipCodes, so they all get posted to the ZipCodes array. When rendering the fields in the loop above, I expect it to read the value of the property at the given index, but that doesn't work. I've even tried remapping the SelectListItems so that the proper option's "Selected" property is true, but it still renders the control with nothing selected. What is going wrong?
The reason you first 2 snippets do not work is that ZipCodes is a property in your model, and its the value of your property which determines what is selected (not setting the selected value in the SelectList constructor which is ignored). Since the value of ZipCodes is an array of values, not a single value that matches one of the option values, a match is not found and therefore the first option is selected (because something has to be). Note that internally, the helper method generates a new IEnumerable<SelectListItem> based on the one you provided, and sets the selected attribute based on the model value.
The reason you 3rd and 4th snippets do not work, is due to a known limitation of using the DropDownListFor() method, and to make it work, you need to use an EditorTemplate and pass the SelectList to the template using AdditionalViewData, or construct a new SelectList in each iteration of the loop (as per your last attempt). Note that all it needs to be is
for(int i = 0; i < Model.ZipCodes.Length; i++)
{
#Html.DropDownListFor(m => m.ZipCodes[i],
new SelectList(Model.ZipCodeOptions, "Value", "Text", Model.ZipCodes[i]))
}
If you want to use just a common name (without indexers) for each <select> element using the DropDownList() method, then it needs to be a name which does not match a model property, for example
foreach(var item in Model.ZipCodes)
{
#Html.DropDownList("SelectedZipCodes",
new SelectList(Model.ZipCodeOptions, "Value", "Text", item))
}
and then add an additional parameter string[] SelectedZipCodes in you POST method to bind the values.
Alternatively, use the for loop and DropDownListFor() method as above, but include a hidden input for the indexer which allows non-zero based, non consecutive collection items to be submitted to the controller and modify you script to add new items using the technique shown in this answer
Note an example of using the EditorTemplate with AdditionalViewData is shown in this answer
i have List view and in every rows it has the "Actualizar" link action and that one takes me to the edit view in which i have some dropdownLists available for updating my existing data but my big problem is that i want the dropdownlist to first load the data is save. how can i set the dropdownlist to load the data of the model a return and let me choose other options
controller:
public ActionResult ActualizarDispositivo(int id )
{
dropDown();
var equipo= _db.equipo.Include(m=>m.marca).Include(mo=>mo.modelo.Single(b => b.idEquipo==id);
ViewBag.idMarca = _db.marca.ToList().Select(Mar => new SelectListItem
{
Value = Mar.idMarca.ToString(),
Text = Mar.Descripcion.ToString(),
Selected = true
});
return View("ActualizarDispositivo",equipo);
}
in the edit view i have this
#Html.DropDownListFor(m=>m.idMarca,(IEnumerable<SelectListItem>)ViewBag.idMarca)
The code you are using should work, if you simply remove the Selected = true. Currently you are setting all of the DropDownList's values to selected.
I'm not sure which performs better, but I do find it more readable to create a select list using:
ViewBag.idMarca = new SelectList(_db.marca.ToList(), "idMarca", "Descripcion");
And then, there may be no need to cast. (Unsure, I avoid the use of ViewBag)
#Html.DropDownListFor(m=>m.idMarca, ViewBag.idMarca)
I have a class, Farm, which contains a list of classes of type Animal.
public class Farm {
public list<Animal> Animals;
// other members..
}
public class Animal {
public string Name;
public string Family;
}
I would like to make a createOrEdit view for my Farm object, and I'd like to use DropDownLists for the Animal's Name and Family. The choices are coming from a database.
When I pass the Animal model to the view for editing I'd like to have the DropDownLists somehow match the properties for each animal and set the selected values of the lists.
I've tried lots of things like this:
#for(int i = 0; i < Model.Animals.Count; i++)
{
#Html.DropDownListFor(model => model.Animals[i].Name, Model.AnimalNames)
// where Model.AnimalNames is a SelectList
#Model.Animals[i].Name // (for testing) this properly displays the name I want to be selected in the list
}
I've seen a bunch of suggestions on this site for creating SelectLists in the controller, iterating through each item and setting the selected property where appropriate. But there's gotta be a cleaner way.. what if I have 100 Animals on my farm. It doesn't seem reasonable to create 200 SelectLists in the controller, iterate through each of them to match up the selected values, and then pass that to the view.
So, is there a simple way for me to take that Animal.Name[i] value and find its matching listitem in the DDL?
Thanks!!
Inside your foreach loop you can do:
#for(int i = 0; i < Model.Animals.Count; i++)
{
var original = Model.AnimalNames;
var animalSelected = new SelectList(original.Items, original.DataValueField, original.DataTextField, model.Animals[i].Name);
#Html.DropDownListFor(model => model.Animals[i].Name, animalSelected)
}
This way, in your controller you create just one SelectList with the AnimalNames... and in your view, you create SelectList with the selected value for each one.
We use this approach when using list of editable items with the need of display the current value of each item.
I'm trying to use a SelectList one of my views, and its just not populating correctly. It gets the proper number of entries (4), but they all read System.Web.Mvc.SelectListItem. I fired up the debugger on the code, and saw some strangeness going on. I must be doing something wrong, but I don't quite see what.
Code from the ViewModel:
public SelectList DeviceTypes {get; private set;}
....
var device_types = DataTableHelpers.DeviceTypes();
IEnumerable<SelectListItem> sl = device_types.Select(
dt => new SelectListItem { Selected = (dt.DeviceType == 1),
Text = dt.Description,
Value = dt.DeviceType.ToString() }).ToList();
DeviceTypes = new SelectList(sl);
And code from the View:
<%= Html.DropDownList("Type",Model.DeviceTypes) %>
So, when I look at this in the debugger, the sl IEnumerable is getting built correctly. I can see all 4 elements in there, with the proper Text and Value property values. Once I call the SelectList constructor however, if I expand the IEnumerable that it contains, I see that it has 4 entries, but all the data in them has been lost. The Text is set to System.Web.Mvc.SelectListItem, and the value is null.
Ive tried changing the ToList() call to a ToArray(), as well as removing it entirely. That didn't change the behaviour.
What am I doing wrong here?
EDIT: Scratch my first answer.
You should be passing the IEnumerable list if items to the View, not trying to construct a Html item in the controller.
Code for controller:
public IEnumberable<YourModel> DeviceTypes {get; internal set;}
....
DeviceTypes = DataTableHelpers.DeviceTypes();
Code for View:
<%= Html.DropDownList("Type", from dt in Model.DeviceTypes
select new SelectListItem
{
Text = dt.Description,
Value = dt.DeviceType.ToString(),
Selected = dt.DeviceType == 1
}) %>
I have a SelectList that I first check for a selected value != null and then want to use this selectedvalue in a where clause for a filter. Like so:
if(searchBag.Qualities.SelectedValue != null){
ListItem selected = (ListItem)searchBag.Qualities.SelectedValue;
}
I made the cast in a seperate useless line to pinpoint the problem.
This gives me a
Unable to cast object of type 'WhereListIterator`1[System.Web.Mvc.ListItem]' to type 'System.Web.Mvc.ListItem'.
Weuh?
--EDIT--
It was indeed because multiple selections were made.
This was because on creation I set the selected value to theItems.Where(i=>i.someCriterea) and I forgot to put .FirstOrDefault() at the end. Ending up in the possibility of multiple answers.
Since it was an IEnumerable, it was a lazy list and hence the WhereListIterator I guess.
I solved it by simple putting FirstOrDefault at the end.
Its already been explained, but here's another suggestion as to how to get what you're looking for:
if(searchBag.Qualities.SelectedValue != null){
ListItem selected = (ListItem)searchBag.Qualities.SelectedValue.FirstOrDefault();
}
I assume the SelectList lets you select more than 1 item?
So SelectedValue is probably a list? Not 1 listitem.
Cast it to:
WhereListIterator<ListItem> selected = (WhereListIterator<ListItem>)searchBag.Qualities.SelectedValue;
instead
and see what properties you have there.
SelectedValue is not a ListItem, it's the value of the selected list item. So given this:
var selectList = new SelectList(companiesList, "Id", "Name", companiesList[3]);
selectList.SelectedValue will equal companiesList[3].Id. If you want the actual list item you can do something like this:
ListItem selected = selectList.GetListItems().Where(x => x.Value == selectList.SelectedValue.ToString())
Just curious, why do you want the selected list item?