1

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>
techspider
  • 3,370
  • 13
  • 37
  • 61
Philip Stratford
  • 4,513
  • 4
  • 45
  • 71
  • Just disable any OnSelectedIndexChanged events using a bool (or de-register the event), then change the SelectedIndex value to 0 for each nulled list. – Shannon Holsinger Aug 31 '16 at 17:09
  • Check this reply: http://stackoverflow.com/questions/9293878/html-dropdownlistfor-how-to-add-option – Fabian Aug 31 '16 at 17:48

1 Answers1

2

This functionality is already built into MVC by using one of the overloads of DropDownList() or DropDownListFor() method that accepts an optionLabel paremeter, for example

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

or for the strongly typed version

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

where the value of the optionLabel will be added as the first option with a null value (generates for example <option value="">Unknown</option>).

I strongly recommend you use the strongly typed version, and that you use a view model with a property for the SelectList rather that using ViewBag, but in any case, do not use the same name for the property you binding to and the ViewBag property (refer this answer for more detail)

Your code should be

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

and in the GET method

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

and in the view

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

If the value of PremisesID is null or does not match one of the ID values from the Premises table, then the first option will be selected.

Community
  • 1
  • 1