ListBoxFor not letting me select multiple items MVC - c#

When I run the code, I can only select one item at a time, that's weird because 'ListBoxFor()' is used to select multiple items, so what i want is:
Select multiple items
View (Index.cshtml):
<div>
#Html.ListBoxFor(m => m.DropDownItems, new MultiSelectList(Repository.DDFetchItems(), "Value", "Text", Model.DropDownItems))
</div>
Model (ModelVariables.cs):
public class ModelVariables
{
public List<SelectListItem> DropDownItems { get; set; }
}
public static class Repository
{
public static List<SelectListItem> DDFetchItems()
{
return new List<SelectListItem>()
{
new SelectListItem(){ Text = "Dogs", Value = "1", Selected = true},
new SelectListItem(){ Text = "Cats", Value = "2"},
new SelectListItem(){ Text = "Death", Value = "3"}
};
}
}
Controller (HomeController.cs):
[HttpGet]
public ActionResult Index()
{
ModelVariables model = new ModelVariables()
{
DropDownItems = Repository.DDFetchItems()
};
return View(model);
}

You cannot bind a <select multiple> to a collection of complex objects (which is what List<SelectListItem> is). A <select multiple> posts back an array of simple values (in your case, if you select the 1st and 3rd options, it will submit [1, 3] (the values of the selected options).
Your model needs a IEnumerable<int> property to bind to.
public class ModelVariables
{
public IEnumerable<int> SelectedItems { get; set; }
public IEnumerable<SelectListItem> DropDownItems { get; set; }
}
and then in the GET method
public ActionResult Index()
{
var ModelVariables= new ModelVariables()
{
DropDownItems = Repository.DDFetchItems(),
SelectedItems = new List<int>(){ 1, 3 } // to preselect the 1st and 3rd options
};
return View(model);
}
and in the view
#Html.ListBoxFor(m => m.SelectedItems, Model.DropDownItems)
Side notes
Remove Selected = true in the DDFetchItems() method - its
ignored by the ListBoxFor() method because its the value of the
property your binding to which determines what is selected
There is not need to build a new identical SelectList from the
first one inside the ListBoxFor() method (property DropDownItems
is already IEumerable<SelectListItem>)

Related

Dropdown selection not getting cleared

I am trying to clear the selected value from the dropdown but still the value is persisting. It is the same behavior using #Html.DropDownListFor
Controller
public class HomeController : Controller
{
[Route("/Home/Index")]
[Route("/Home/Index/{Category}")]
[Route("/Home/Index/{Category}/{Type}")]
public IActionResult Index(HomeModel model)
{
// Issue is here
// for url: home/index/accessories/test
// "Category" is cleared if it is not valid "type"
// but still "Accessories" remains selected in the drop down
if (model.Type != "Electronics" && model.Type != "Furniture")
{
model.Category = string.Empty;
}
return View(new HomeModel() { Category = model.Category, Type = model.Type });
}
View
#model WebApplication1.Controllers.HomeModel
<select asp-for="Category" asp-items="#Model.Categories"></select>
<select asp-for="Type" asp-items="#Model.Types"></select>
Model
public class HomeModel
{
public string Category { get; set; }
public string Type { get; set; }
public List<SelectListItem> Categories { get; set; } = new List<SelectListItem>
{
new SelectListItem() { Text="Computers & Laptops", Value="Computers-Laptops" },
new SelectListItem() { Text="Accessories", Value="Accessories" },
};
public List<SelectListItem> Types { get; set; } = new List<SelectListItem>
{
new SelectListItem() { Text="Electronics", Value="Electronics" },
new SelectListItem() { Text="Furniture", Value="Furniture" },
};
}
UPDATE
I tried to add a empty value to the Category dropdown and still no luck.
<select asp-for="Category" asp-items="#Model.Categories">
<option value="">Select Category</option>
</select>
The issue is within the ModelState. What happens is that when the URL parameters are bound to the view model, the values are added to the model state dictionary. When the view is rendered, not only your HomeModel is passed to the view, but underneath the scenes the ModelState is passed as well - and it has a higher priority than the view model. So while you reset the model.Category, the Category key in the ModelState still has the value accessories and that is why it is being selected in the dropdown.
The solution is simple, call .Clear() to wipe out the model state and make your view model win:
[Route("/Home/Index")]
[Route("/Home/Index/{Category}")]
[Route("/Home/Index/{Category}/{Type}")]
public IActionResult Index(HomeModel model) {
// Issue is here
// for url: home/index/accessories/test
// "Category" is cleared if it is not valid "type"
// but still "Accessories" remains selected in the drop down
if (model.Type != "Electronics" && model.Type != "Furniture") {
model.Category = string.Empty;
}
ModelState.Clear();
return View(new HomeModel() { Category = model.Category, Type = model.Type });
}

How to select values in a multiple DropDownList using DropdownListFor in MVC 5

I have this model:
public class CampoTipoDocumentoViewModel
{
public int TipoDocumentoId { get; set; }
public string[] CamposId { get; set; }
private List<MiddleTier.Models.ICampo> _todosCampos;
public IEnumerable<SelectListItem> TodosCampos
{
get
{
foreach (var campo in _todosCampos)
yield return new SelectListItem { Text = campo.Nombre, Value = campo.Id.ToString() };
}
}
public void SetFields(List<MiddleTier.Models.ICampo> campos)
{
_todosCampos = campos;
}
}
In controller, CamposId property is assigned with elements which has to be selected in the view.
Controller also calls SetFields method populating _todosCampos to the whole list of records in the system.
The idea is to create a View with a SELECT that has initially some records selected.
This is my view:
#Html.DropDownListFor(m => m.CamposId, Model.TodosCampos, new { #class = "form-control", multiple = "multiple", width = "100%" })
The fact is that the HTML SELECT element is created with the list, but no option is selected.
For example, if _todosCampos contains:
Text = "One", Value = "1"
Text = "Two", Value = "2"
Text = "Three", Value = "3"
Text = "Four", Value = "4"
and CamposId contains:
Array of "2", "4"
I need the view to create a SELECT with those 4 options, and option 2 and 4 to be initially selected.
How can I achieve this?
Thanks
Jaime
In order to use <select> element with multiple="multiple" attribute, you need to declare List<string> property:
public List<string> CamposId { get; set; }
And then use ListBoxFor helper instead of DropDownListFor:
#Html.ListBoxFor(m => m.CamposId, Model.TodosCampos, new { #class = "form-control", multiple = "multiple", width = "100%" })
If you want to set some option values are selected by default, then set Selected property into SelectListItem:
public IEnumerable<SelectListItem> TodosCampos
{
get
{
foreach (var campo in _todosCampos)
{
// assumed you have 'campo.IsDefault' which is boolean property
yield return new SelectListItem
{
Text = campo.Nombre,
Value = campo.Id.ToString(),
Selected = campo.IsDefault // set default selected values
};
}
}
}
Note: Usually ID property contain integer values, you can try for List<int> CamposId depending on actual ID data type in database.

Get selected item in a dropdown list in view to CRUD model

This is done by adding a view from my controller and selecting my dto as template
My DTO
public class Company_DTO
{
public long ID_Company { get; set; }
public string ESTATE_Company { get; set; }
}
MyController
public ActionResult UpdateCompany()
{
ViewBag.ListOfCompanies = DependencyFactory.Resolve<ICompanyBusiness>().GetCompany(); // this return a List<int> and following what I read for viewbag this should be right.
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UpdateCompany([Bind]Company_DTO company_DTO)
{
try
{
//code
}
catch
{
return View();
}
}
View
<div class="form-group">
#Html.DropDownListFor(model => model.ID_Company , ViewBag.ListOfCompanies) // Here I get an error on my #Html that my dto does nothave a list.
</div>
I want the selected item to be ID_Company, but here it seems to be trying to add the whole list when I just want the selected item, I cant find any documentation or question that can solve my issue.
I Cant EDIT the DTO.
Thanks for any help and hope I am being clear enough.
This should solve your problem:
View
<div class="form-group">
#Html.DropDownListFor(model => model.ID_Company, new SelectList(ViewBag.Accounts, "ID_Company", "ESTATE_Company"))
</div>
Supposing your view is strongly typed (#model Company_DTO).
Hope this helps
consider the following example:
public class HomeController : Controller
{
private List<SelectListItem> items = new List<SelectListItem>()
{
new SelectListItem() { Text = "Zero", Value = "0"},
new SelectListItem() { Text = "One", Value = "1"},
new SelectListItem() { Text = "Two", Value = "2"}
};
public ActionResult Index()
{
ViewBag.Items = items;
return View(new Boo() { Id = 1, Name = "Boo name"});
}
}
public class Boo
{
public int Id { get; set; }
public string Name { get; set; }
}
the view:
#model WebApi.Controllers.Boo
#Html.DropDownListFor(x=>x.Id, (IEnumerable<SelectListItem>) ViewBag.Items)
so, ViewBag.ListOfCompanies should contain IEnumerable. Each SelectListItem has Text and Value property , you need to assign ESTATE_Company and ID_Company respectively. something like this:
var companiesList = //get companies list
ViewBag.ListOfCompanies = companiesList.Select(x => new SelectListItem() {Text = x.ESTATE_Company, Value = x.ID_Company.ToString()});
....
#Html.DropDownListFor(x=>x.ID_Company, ViewBag.Items as IEnumerable<SelectListItem>)

Bindig ListBox selection to model properties

I've been struggling to bind a MultiSelectList from Html helper to a specific model.
Model
In my model I have something like this:
public class DefaultSelection
{
public SelectionItem Selection1 {get;set;}
public SelectionItem Selection2 {get;set;}
public SelectionItem Selection3 {get;set;}
public IEnumerable<SelectionItem> Items{get;set;}
public DefaultSelection()
{
Selection1 = new SelectionItem(true, "Item1");
Selection2 = new SelectionItem(false, "Item2");
Selection3 = new SelectionItem(true, "Item3");
Items = new List<SelectionItem>(new SelectionItem[]
{Selection1,Selection2,Selection3});
}
}
public class SelectionItem
{
public bool Selected {get;set;}
public string Name {get;set;}
public SelectionItem(bool selected, string name)
{
Selected = selected;
Name = name;
}
}
What I want to do is binding my ListBox selection to Selected property of a SelectionItem.
I've tried this in my View:
#Html.ListBoxFor(model => model.Items, new MultiSelectList( Model.Items, Model.Items.Where(item => item.Selected)), new { #class = "selectpicker" })
Unfortunatly neither the selected items are shown properly (nothing is selected) nor has a selection any effects on the model...
Is there a way to solve this?
Can I get rid of this Items property for it is just a reference to the needed properties?
I think it's a lot easier than you think. Let's give this a try.
Create a good view model:
public class DefaultSelection
{
public IEnumerable<SelectListItem> Items { get; set; }
//Set a property to hold the selected items IDs.
public IEnumerable<string> SelectedItems { get; set; }
public DefaultSelection()
{
//preselected features
Items = new List<SelectListItem>
{
new SelectListItem { Text = "Item1", Selected = true},
new SelectListItem { Text = "Item2", Selected = false},
new SelectListItem { Text = "Item3", Selected = true}
};
}
}
Render the ListBox in the view:
<div class="form-group">
#Html.LabelFor(x => x.Items)
#Html.ListBoxFor(x => x.SelectedItems, Model.Items, new { #class = "selectpicker" })
</div>
Note that I'm using here the built-in System.Web.Mvc.SelectListItem class instead of your custom one SelectionItem- you can safely get rid of it.
Now you'll get the selected items id's (in this case the name, because you didn't specify value property when create the items) in your model after posting.
Hope this helps!
your #Html.ListBoxFor should be like this
#Html.ListBoxFor(model => model.SelectedNames, new MultiSelectList(Model.Items,"Name", "Name",Model.Items.Where(x=>x.Selected).Select(x=>x.Name)), new { #class = "selectpicker" })
you have to specify Value field and Text field of Model.Items which is "Name", "Name" and Model.Items.Where(x=>x.Selected).Select(x=>x.Name) will select all the values where selected is true but your model will return the values in list of string so you should define a field
public List<string> SelectedNames { get; set; }
where you will get the values of the selected items

Getting Multiple Selected Values in Html.DropDownlistFor

#Html.DropDownListFor(m => m.branch, CommonMethod.getBranch("",Model.branch), "--Select--", new { #multiple = "multiple" })
#Html.DropDownListFor(m => m.division, CommonMethod.getDivision(Model.branch,Model.division), "--Select--", new { #multiple = "multiple" })
I have two instances of DropDownListFor. I want to set selected as true for those which have previously stored values for Model.branch and Model.division. These are string arrays of stored ids
class CommonMethod
{
public static List<SelectListItem> getDivision(string [] branchid , string [] selected)
{
DBEntities db = new DBEntities();
List<SelectListItem> division = new List<SelectListItem>();
foreach (var b in branchid)
{
var bid = Convert.ToByte(b);
var div = (from d in db.Divisions where d.BranchID == bid select d).ToList();
foreach (var d in div)
{
division.Add(new SelectListItem { Selected = selected.Contains(d.DivisionID.ToString()), Text = d.Description, Value = d.DivisionID.ToString() });
}
}
}
return division;
}
}
The returned value of division is selected as true for the selected item in the model, but on view side it is not selected.
Use a ListBoxFor instead of DropDownListFor:
#Html.ListBoxFor(m => m.branch, CommonMethod.getBranch("", Model.branch), "--Select--")
#Html.ListBoxFor(m => m.division, CommonMethod.getDivision(Model.branch, Model.division), "--Select--")
The branch and division properties must obviously be collections that will contain the selected values.
And a full example of the proper way to build a multiple select dropdown using a view model:
public class MyViewModel
{
public int[] SelectedValues { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
that would be populated in the controller:
public ActionResult Index()
{
var model = new MyViewModel();
// preselect items with values 2 and 4
model.SelectedValues = new[] { 2, 4 };
// the list of available values
model.Values = new[]
{
new SelectListItem { Value = "1", Text = "item 1" },
new SelectListItem { Value = "2", Text = "item 2" },
new SelectListItem { Value = "3", Text = "item 3" },
new SelectListItem { Value = "4", Text = "item 4" },
};
return View(model);
}
and in the view:
#model MyViewModel
...
#Html.ListBoxFor(x => x.SelectedValues, Model.Values)
It is the HTML helper that will automatically preselect the items whose values match those of the SelectedValues property.
For me it works also for #Html.DropDownListFor:
Model:
public class MyViewModel
{
public int[] SelectedValues { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
Controller:
public ActionResult Index()
{
var model = new MyViewModel();
// the list of available values
model.Values = new[]
{
new SelectListItem { Value = "2", Text = "2", Selected = true },
new SelectListItem { Value = "3", Text = "3", Selected = true },
new SelectListItem { Value = "6", Text = "6", Selected = true }
};
return View(model);
}
Razor:
#Html.DropDownListFor(m => m.SelectedValues, Model.Values, new { multiple = "true" })
Submitted SelectedValues in controller looks like:
Though quite old thread but posting this answer after following other answers here, which unfortunately didn't work for me. So, for those who might have stumbled here recently or in near future, Below is what has worked for me.
This is what helped me
The catch for me was MultiSelectList class and I was using SelectList.
Don't know situation in 2012 or 2015. but, now both these helper methods #Html.DropDownListFor and #Html.ListBoxFor helper methods accept IEnumerable<SelectListItem> so you can not pass any random IEnumerable object and expect these helper methods to do the job.
These helper methods now also accept the object of SelectList and MultiSelectList classes in which you can pass the selected values directly while creating there objects.
For example see below code how i created my multi select drop down list.
#Html.DropDownListFor(model => #Model.arrSelectUsers, new MultiSelectList(Model.ListofUsersDTO, "Value", "Text", #Model.arrSelectUsers),
new
{
id = "_ddlUserList",
#class = "form-control multiselect-dropdown",
multiple = "true",
data_placeholder = "Select Users"
})

Categories

Resources