On my asp.net-mvc page, why is the right dropdown menu not selected?

I have an asp.net-mvc website and I ran into a problem when the correct selected item in the drop down list is not selected. I have the following code for my action with a controller (simplified to highlight the problem):

public ActionResult MyAction() { var vm = GetVM(); var list = new List<INamed> {new NamedInfo() {Id = 1, Name = "Yes"}, new NamedInfo() {Id = 0, Name = "No"}}; vm.YesNoList = SelectListHelper.GenerateDropdownList(vm.IncludesWeekends ? 1 : 0, list); return View(vm); } 

and here is the definition of GenerateDropdownList

  public static List<SelectListItem> GenerateDropdownList<T>(int id, IEnumerable<T> list) where T : INamed { List<SelectListItem> dropdown = list.Select(c => new SelectListItem { Selected = c.Id == id, Text = c.ToString(), Value = c.Id.ToString() }).ToList(); return dropdown; } 

The following is the code in my HTML view:

  <% = Html.DropDownList("IncludesWeekends", Model.YesNoList, new { @id = "IncludesWeekends" })%> 

I expect No to be selected in my example (and it selected = true when I set a breakpoint on the server side, but when I look at the html that is generated, nothing is selected:

 <select id="IncludesWeekends" class="autoComplete1" name="IncludesWeekends"> <option value="1">Yes</option> <option value="0">No</option> </select> 

and "Yes" is selected by default because its first element.

Any suggestions on what I'm doing wrong here or alternatives that work?

+4
source share
5 answers

The Selected property in SelectListItem is mostly useless (more on that in my answer) . In most cases, HTML helpers will ignore it. Instead, in your case, they will look at the values:

  • ModelState["IncludesWeekends"]
  • ViewData["IncludesWeekends"]
  • Model.IncludesWeekends

... and turn any value they find into String , and then use it as the selected value.

You have the IncludesWeekends property on your model, so it will do:

 Model.IncludesWeekends.ToString() 

... which - judging by your code - will result in True "or" False "(since it is a bool ).

In your case, you use c.Id.ToString() as the <option> values โ€‹โ€‹for your drop-down list, and since the helper will not find your selected row ("True" / "False") among these values โ€‹โ€‹("1" / "0 "), he will not choose anything.

Ways around him:

  • (The easiest way): Accept the values โ€‹โ€‹"True" and "False" as your <option> values, not integer identifiers.

  • (Almost as simple, but not very clean): set ViewData["IncludesWeekends"] to the value you want to select (i.e. Id ). This works because the helper will look at it before Model.IncludesWeekends .

  • Use a view model where you have the IncludesWeekendsId property, then use this to create a dropdown, not IncludesWeekends :

    <%= Html.DropDownList("IncludesWeekendsId", Model.YesNoList) %>

    or

    <%= Html.DropDownListFor(m => m.IncludesWeekendsId, Model.YesNoList) %>

    Then, returning from the view, translate IncludesWeekendsId back to the desired value on your model.

In this case, I would probably go with 1 if I were not in a pedantic mood. But solution 3 is a general and basically clean way to solve this problem, when you need to use different values โ€‹โ€‹for the dropdown elements than the value of the model property converted to a string.

+2
source

Try using Html.DropDownListFor-helper instead:

 @Html.DropDownListFor(c => c.Id, Model.YesNoList) 

Forget about Selected = c.Id == id in:

  List<SelectListItem> dropdown = list.Select(c => new SelectListItem { Selected = c.Id == id, Text = c.ToString(), Value = c.Id.ToString() }).ToList(); 

Put your viewing model, if possible.

And I would recommend using Razor syntax, if you are able to change, your looks look much cleaner! <% Html.DropDown....) %> becomes @Html.DropDown...)

+1
source

Your code will be much cleaner if you used an enumeration for this. I suggest you use this approach, instead it creates a cleaner and more consistent code: fooobar.com/questions/1167564 / ...

+1
source

I would advise you to use such a type-safe design:

 <% = Html.DropDownListFor(x => x.IncludesWeekends, new SelectList(Model.YesNoList, "Value", "Text"), new { @id = "IncludesWeekends" })%> 

instead of this:

 <% = Html.DropDownList("IncludesWeekends", Model.YesNoList, new { @id = "IncludesWeekends" })%> 

You get a lot - a strongly typed lambda expression bound to a given property of the model, instead of the name of the property hardcoded as a magic string. Using this construct, you automatically get intelli-sense tools, refactoring, and compiler support. Strongly typed helpers exist in MVC since version 2.0, so it makes no sense to use the old ones.

Next, change the value of the IncludesWeekends model to pre-select the desired parameter. In your case, this means changing the type of IncludesWeekends to string instead of bool and assigning it the value "0" or "1" . Alternatively, if you do not want to change the IncludesWeekends type, add an additional property to your model, for example. SelectedValue and make minor changes:

In action:

 vm.SelectedValue = vm.IncludesWeekends ? "1" : "0"; 

in view:

 Html.DropDownListFor(x => x.SelectedValue, ... 

You do not need to use the Selected SelectListItem property - ignore it and remove all references to it.

+1
source
  public ActionResult Index() { ViewModel vm = new ViewModel(); vm.IncludesWeekends = false; var list = new List<INamedInfo> { new NamedInfo() { Id = 1, Name = "Yes" }, new NamedInfo() { Id = 0, Name = "No" } }; vm.YesNoList = GenerateDropdownList(vm.IncludesWeekends ? 1 : 0, list); vm.IncludesWeekendsValue = vm.IncludesWeekends ? 1 : 0; return View(vm); } public class ViewModel { public List<SelectListItem> YesNoList { get; set; } public bool IncludesWeekends { get; set; } public int IncludesWeekendsValue { get; set; } } <% = Html.DropDownListFor(m => m.IncludesWeekendsValue, Model.YesNoList, new { @id = "IncludesWeekends" })%> 
0
source

Source: https://habr.com/ru/post/1496443/


All Articles