I used scaffolding to get a simple MVC page and it produced code like this from my model:
ViewData["CustomersNo"] = new SelectList(_context.Customers, "CustomersId", "Name");
Then I scaffolded the view which produced markup like this:
<div class="form-group">
<label asp-for="CustomersNo" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="CustomersNo" class ="form-control" asp-items="ViewBag.CustomersNo"></select>
</div>
</div>
And when rendered it produced a dropdown control with my customers from my database. Exactly what I wanted and I didn't even have to write a line of code.
But now I want to create a dropdown on a more customized view using filtered data. No matter what I do, it renders as a multiselect which I definitely do not want.
I want to use a View Model but I've also tried ViewData since that is what the scaffolding used:
proViewModel.Vols = new SelectList(_context.Products.Where(t => t.Type == "Volume"), "ModelId", "ModelId");
ViewData["VolModels"] = new SelectList(_context.Products.Where(t => t.Type == "Volume"), "ModelId", "ModelId");
My View Model is pretty simple so far:
public class ProductsViewModel
{
[Key]
public int ID { get; set; }
[NotMapped]
//public IEnumerable<string> Vols { get; set; }
//public IEnumerable<SelectListItem> Vols { get; set; }
public SelectList Vols { get; set; }
[NotMapped]
public string SelectedModel { get; set; }
}
I tried different IEnumerable
types since that was what most tutorials used. But the scaffolding uses SelectList
and this SO Q&A as well as this tutorial both say that IEnumerable
will create a multiselect and seem to suggest using SelectList
.
But with this markup, all I can get is multiselect:
<td>
<div class="form-group">
<label asp-for="Vols" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="Vols" class="form-control" asp-items="Model.Vols"></select>
</div>
</div>
</td>
<td>
<div class="form-group">
<label asp-for="Vols" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="Vols" class="form-control" asp-items="ViewBag.VolModels"></select>
</div>
</div>
</td>
I can't see a difference between what the scaffolding is doing and what I am doing. But the rendered output is completely different and not what I want. So what am I missing here?
You cannot bind a <select>
to a collection of complex objects, which is what Vols
is. A <select>
binds to, and posts back a simple type and a <select multiple>
binds to, and posts back an array of a simple type.
In addition, the name of the property your binding to and the name of the SelectList
cannot be the same (refer Can the ViewBag name be the same as the Model property name in a DropDownList? for more detail).
Because the property your binding to is IEnumerable
, a <select multiple>
is created.
Change your code to
<div class="form-group">
<label asp-for="SelectedModel" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="SelectedModel" class="form-control" asp-items="Model.Vols"></select>
</div>
</div>
and the selected option value will be bound to the SelectedModel
property.
As a side note, remove your [Key]
and [NotMapped]
attributes - they a EF specific attributes and have no place in a view model.