0

I'm currently working on a app which is being developed using C# and Asp.Net MVC.

On one of the views I have around 10 DropDowns which users must select. The selected value is stored into the database.

For Example:

  1. DropDown has Value of 1 and Text appears as First Main Fault
  2. DropDown has Value of One and Text appears as First Sub Fault

Now users can come back and edit their records. So I want to show them the DropDown which is already selected with the value of what's stored in the database.

For this I make use of the following extension method

public static IEnumerable<SelectListItem> ToSelectListItems<T>(this IEnumerable<T> items, Func<T, string> textSelector, Func<T, string> valueSelector, Func<T, bool> selecter)
{
   return items.OrderBy(item => textSelector(item))
      .Select(item =>
       new SelectListItem
       {
          Selected = selecter(item),
          Text = textSelector(item),
          Value = valueSelector(item)
        });
}

Which I call as

var mainFaultSelectedDdl = mainFaults.ToSelectListItems(
            m => m.MainFaultDescription,
            m => m.Id.ToString(),
            m => m.Id == mainFaultId); //mainFaultId here equals to 1. I've also tried m.Id.ToString() == mainFaultId.ToString() but still the same issue

var subFaultSelectedDdl = subFaults.ToSelectListItems(
            s => s.SubFaultDescription,
            s => s.SubFaultDescription,
            s => s.SubFaultDescription == erst.SubFault); //erst.SubFault here equals to One

When I debug my code I can see both of the above DropDowns Selected is set to True but in the view The MainFault DropDown doesn't be selected but the SubFault DropDown is selected.

Can someone tell me where I'm going wrong please.

This is how I'm currently generating the DropDown in the view

@Html.DropDownListFor(m => m.Serial.MainFault, Model.MainFaultDdl, "Please select a main fault", new { id = "mainFaults", @class = "form-control main-ddl" })
@Html.DropDownListFor(m => m.Serial.SubFault, Model.SubFaultDdl, "Please select a sub fault", new { id = "subFaults", @class = "form-control main-ddl" })
Izzy
  • 6,740
  • 7
  • 40
  • 84
  • How are you generating your dropdownlists in the view. Setting the `Selected` property of `SelectListItem` is ignored when you bind to a model –  Dec 15 '16 at 11:54
  • where do you set the value for `mainFaultId` and `erst.SubFault`? – MakePeaceGreatAgain Dec 15 '16 at 11:56
  • @StephenMuecke I've updated my question to include the code from the view. It works for one and not the other that's what's confusing me – Izzy Dec 15 '16 at 11:56
  • @HimBromBeere `mainFaultId` is set just before I call my extension method and same with `erst.SubFault` – Izzy Dec 15 '16 at 11:57
  • You binding to the `MainFault` and `SubFault` properties, and its their value which determines the option that is selected (internally the `DropDownListFor()` method builds its own `SelectList` so your code that sets the `Selected` property is pointless) –  Dec 15 '16 at 11:59
  • @StephenMuecke What would be the most appropriate way to go about this then? – Izzy Dec 15 '16 at 12:01
  • If the value of `Serial.MainFault` is (say) `1` and your have an option that has `value="1"` then that option will be selected. You just need to set the value of `MainFault` in the GET method before you pass the model to the view –  Dec 15 '16 at 12:02
  • And there is already a built in method for generating a `SelectList` - using `new SelectList(mainFaults, "Id", "MainFaultDescription")` –  Dec 15 '16 at 12:03
  • @StephenMuecke So i've been over complicating it for no reason :/ – Izzy Dec 15 '16 at 12:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/130689/discussion-between-stephen-muecke-and-code). –  Dec 15 '16 at 12:10

1 Answers1

1

Model binding works by binding to the value of your property, in your case the value of Serial.MainFault. If the value of Serial.MainFault matches one of option values (defined by the value of the Id property of the objects in mainFaults) then it will be selected. If it does not match a value, then the first option will be selected because something has to be.

Setting the Selected property of SelectListItem is ignored when using the DropDownListFor() method because internally the method builds its own IEnumerable<SelectListItem> and sets the Selected property based on the value of the property your binding to (note that there is an exception to this - in the case of using DropDownListFor() in a loop as described in this answer).

However, your extension methods do not seem necessary since MVC already has a method for building an IEnumerable<SelectListItem> using one of the SelectList constructors.

Based on the code you have shown, your GET method can simply be

var model = new YourModel();
model.Serial.MainFault = mainFaultId; // set the value to be displayed initially
model.MainFaultDdl = new SelectList(mainFaults, "Id", "MainFaultDescription"); // generate the options
return View(model);

or alternatively you can use the following to generate the options

model.MainFaultDdl = mainFaults.Select(x => new SelectListItem()
{
    Value = x.Id.ToString(),
    Text = x.MainFaultDescription
};

and the correct option will be displayed in the view.

Community
  • 1
  • 1