0

I try to populate a DropDownListFor in my view, but I don't seem to get it working.

My Model

public class Warehouse
{
    public int Id { get; set; }
    public string Description { get; set; }
    public string LocationCode { get; set; }
    public IEnumerable<SelectListItem> LocationList
    {
        get
        {
            DbEntities db = new DbEntities();

            var List = new SelectList(db.Locations, "LocID".Trim(), "Desc".Trim());
            return List;
        }
        set { }
    }
}

In my ViewPage I have the following code

@model IEnumerable<MyApp.Models.Warehouse>

<!-- some html -->
@foreach(var s in Model)
{
    @Html.DropDownListFor(p => s.LocationCode, s.LocationList, "", new { @class = "form-control" })
}

I thought by setting p => s.LocationCode I set the initial selected value for the dropdownlist (the selected value should be empty if s.LocationCode == null), but my result is that all drop-down boxes are have an initial empty value (and when I click on one of them, you see that the dropdownlist is populated).

ataravati
  • 8,891
  • 9
  • 57
  • 89
kwv84
  • 943
  • 3
  • 11
  • 25
  • There are too many similar question in SO. Look at this one, for example: http://stackoverflow.com/questions/16034454/create-many-dropdownlistfor-in-foreach-loop – ataravati Nov 19 '15 at 21:15

1 Answers1

0

Firstly this will not bind when you submit. You cannot generate form controls in a foreach loop because it generates duplicate name attributes which have no relationship to your model (it also generating invalid html because of the duplicate id attributes. If you inspect the html you will see that its

<select name="s.LocationCode" ... >
<select name="s.LocationCode" ... >

where as it needs to be

<select name="[0].LocationCode" ... >
<select name="[1].LocationCode" ... >

Your loop needs to be

@model List<MyApp.Models.Warehouse> // must implement IList<T>
....
@for(int i = 0; i < Model.Count; i++)
{
  @Html.DropDownListFor(m => m[i].LocationCode, Model[i].LocationList, ...)

Another alternative is to use a custom EditorTemplate for typeof Warehouse

In /Views/Shared/EditorTemplates/Warehouse.cshtml

@model Warehouse
....
@Html.DropDownListFor(m => m.LocationCode, Model.LocationList, ...)

and then in the main view

@model IEnumerable<MyApp.Models.Warehouse> // can be Enumerable<T>
....
@Html.EditorFor(m => m)
  • I've tried what you are describing above, but then I can't use SelectList(Model.LocationList because it says my model does not contains a definition. – kwv84 Nov 19 '15 at 21:55
  • Oops - I have just realized your SelectList is actually inside the model (unusual) so in this case it would need to be just `@Html.DropDownListFor(m => m[i].LocationCode, Model[i].LocationList)` - generating a new `SelectList` is not strictly necessary. The main issue is your incorrect use of a `foreach` loop which will not give 2-way model binding –  Nov 19 '15 at 21:57
  • I would also consider changing the way you are doing this. Accessing a database in a model like that is not good practice. Makes it impossible to unit test unless you inject it using DI –  Nov 19 '15 at 22:00
  • Solved it. I've changed my (View) Model to just have `public IEnumberableLocationList {get; set;}`. In my controller I populate the list and set the selectedValue. In my View(cshtml) I have `@Html.DropDownListFor(m => m[i].LocationCode, Model[i].LocationList, string.Empty, new {@class = "form-control"})` (and changed my foreach loop to a for loop. – kwv84 Nov 20 '15 at 10:43