clement
clement

Reputation: 4266

DropDownList doesn't want to be set

My dropDown list doesn't want to have default value!

<div class="form-group">
            @Html.LabelFor(model => model.unit, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(x => x.unit.id, selectUnit)
                @Html.ValidationMessageFor(model => model.unit.id, "", new { @class = "text-danger" })
            </div>
        </div>

Show me the right list but none is selected.

I get my SelectList by using ViewBag:

@{
    IEnumerable<SelectListItem> selectUnit = ViewBag.Unit;
}

When I breakpoint the cshtml, Model.unit.id is 4 and selectUnit have one item with 4 as value.

When I do

@selectUnit.Where(x => x.Value == Model.unit.id.ToString()).First().Text

it selects the right text value!

Lats think: this is my Unit model:

public class Unit
{
    public int id { get; set; }
    public string name { get; set; }
    public string description { get; set; }
    public IList<Unit> children { get; set; }
}

Thanks in advance folks, I'm becoming crasy

EDIT:

public class ModelPassedTroughTheView
{
    ...
    public Unit unit { get; set; }
}

EDIT 2: Full code:

Edit page: @model BE.DealerGroupSAP

@{
    ViewBag.Title = Resources.Admin.DealerGroup_Edit;

    IEnumerable<SelectListItem> selectUnit = ViewBag.Unit;
}

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>@ViewBag.Title</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.id)

        <div class="form-group">
            @Html.LabelFor(model => model.unit, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(x => x.unit.id, selectUnit)
                @Html.ValidationMessageFor(model => model.unit.id, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="@Resources.Global.Save_Edits" class="btn btn-default" />
            </div>
        </div>
    </div>
}

Model passer trough view:

public class DealerGroupSAP
{
    public int id { get; set; }
    public Unit unit { get; set; }
}

Unit object:

public class Unit
{
    public int id { get; set; }
    public string name { get; set; }
    public string description { get; set; }
    public IList<Unit> children { get; set; }
}

Controller's content:

ViewBag.Unit = GetUnits();
return View(BL.AnomalyBL.GetAllSAPResponsible(id));

Upvotes: 2

Views: 77

Answers (1)

user3559349
user3559349

Reputation:

The issue is that your model has a property named unit and your also passing the SelectList view a ViewBag property named Unit (the model binding features of MVC are case insensitive.

Change the name of the ViewBag property to (say)

ViewBag.UnitList = GetUnits();

and in the view

@{ IEnumerable<SelectListItem> selectUnit = ViewBag.UnitList }

and the correct option will be selected.


To explain what is happening internally:

The DropDownListFor() method determines the defaultValue (selected item) by first checking values in ModelState (which in your case do not exist), then checking ViewData. Because ViewData contains a key/value pair for Unit, which is IEnumerable<SelectListItem> and does not contain a property id, the defaultValue is nulland the method uses the IEnumerable<SelectListItem> you passed to the view to build the <option> elements, none of which have a Selected = true value, so the first option is selected because something has to be.

Changing the ViewBag property to to (say) UnitList means the method does not find a matching key for unit in ViewData and now inspects the model for unit.id, which exists, and sets defaultValue = 4. Because defaultValue is not null, a new IEnumerable<SelectListItem> is generated internally, and the corresponding SelectListItem has its Selected property set to true.

To understand how this all works in detail, you can inspect the source code for SelectExtensions - in particular the private static MvcHtmlString SelectInternal() method.

As a final note, this is just one more reason why you should always use a view model.

Upvotes: 2

Related Questions