Add empty option to DropDownList when database value is NULL

时间:2016-08-31 17:07:08

标签: c# jquery asp.net asp.net-mvc razor

I have a database table with several foreign key fields. When I load a record for editing, there are dropdown lists, created in Razor using @Html.DropDownList, which correctly display the possible values from the table which the foreign key columns reference. And, because I'm editing a record, if a value has previously been selected from the foreign key table, its ID is in the foreign key column of my primary table, as you'd expect.

However, if the record I'm loading for editing does NOT have a value in one of the foreign key columns - i.e., the value in a column is NULL (and they're all nullable, for reasons beyond my control), the dropdowns by default have the first option selected. Not only is this misleading, because there's no way to know if the option is being displayed because it was previously saved or because it's simply the first option, it also means that when I subsequently save the record, the value of that first option is incorrectly saved to the database.

What I need is for each dropdown list to also include an "Unknown" option, added dynamically (i.e. not in the database), which is selected when the page loads if the underlying foreign key column has a NULL value, and which can be selected by the user if they want to change a previously saved value to NULL.

I have had no trouble adding a value to the dropdowns using jQuery when the page loads, like this:

$("select").prepend("<option value=''>Unknown</option>")

However, when the page loads, even though this new option is successfully added as the first option in the list, it is not selected. The first 'real' option is. And, even though I can force the 'dummy' option to be selected using jQuery, that also selects the dummy option in dropdowns where a real value exists in the database.

This really doesn't seem like something that should be unusual or obscure, and yet I've struggled to find any solutions after an afternoon's Googling. I've tried various things from Stack Overflow which I thought I might be able to make work, but to no avail.

Can anyone suggest a solution? I think adding a 'dummy' option in the controller might be the neatest way, if I could figure out how to. I'm surprised this isn't a very common problem!

The code in my controller which is loading the dropdown lists' values looks like this:

ViewBag.PremisesID = new SelectList(db.Premises, "ID", "StreetName", colicCase.PremisesID);

The corresponding Razor for the dropdown looks like this:

<div class="form-group">
     @Html.LabelFor(model => model.PremisesID, htmlAttributes: new { @class = "control-label col-md-4" })
     <div class="col-md-8">
         @Html.DropDownList("PremisesID", null, htmlAttributes: new { @class = "form-control" })
         @Html.ValidationMessageFor(model => model.PremisesID, "", new { @class = "text-danger" })
    </div>
</div>

1 个答案:

答案 0 :(得分:2)

此功能已经内置到MVC中,使用了接受DropDownList()参数的DropDownListFor()optionLabel方法的重载之一,例如

public static MvcHtmlString DropDownList(
    this HtmlHelper htmlHelper,
    string name,
    IEnumerable<SelectListItem> selectList,
    string optionLabel,
    object htmlAttributes
)

或强类型版

public static MvcHtmlString DropDownListFor<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TProperty>> expression,
    IEnumerable<SelectListItem> selectList,
    string optionLabel,
    object htmlAttributes
)

其中optionLabel的值将作为第一个选项添加null值(例如生成<option value="">Unknown</option>)。

我强烈建议您使用强类型版本,并使用view model使用SelectList的属性,而不是使用ViewBag,但无论如何,请勿使用您绑定的属性和ViewBag属性的名称相同(有关详细信息,请参阅this answer

您的代码应为

public class MyViewModel
{
    ....
    public int? PremisesID { get; set; }
    public IEnumerable<SelectListItem> PremisesList { get; set; }
    ....
}

和GET方法

var model = new MyViewModel()
{
    .... // map properties from the data model
    PremisesID = dataModel.PremisesID,
    PremisesList = new SelectList(db.Premises, "ID", "StreetName")
};
return View(model);

并在视图中

@Html.DropDownListFor(m => m.PremisesID, Model.PremisesList, "Unknown", new { @class = "form-control" })

如果PremisesID的值为null或与ID表中的Premises值之一不匹配,则会选择第一个选项。