0

I'm trying to generate a DropDownList for each record in a table in a View. I have trouble setting the selected value for the dropdownlist.

In the controller each user's access level list in the model is populated by calling a method in the Repository. I can't seem to get this method quite right. I can change the selected value on item, and accessLevels has correct value selected. But in the view this is not the selected value. How can I set the selected value of a selectlist?

I've tried this:

Repository:

public IEnumerable<SelectListItem> GetSelectListAccessLevelsWithSelectedItem(string selectedAccessLevelID)
        {

            IEnumerable<SelectListItem> accessLevelsFromDB = DB.AccessLevels
              .Select(x => new SelectListItem
              {
                  Value = x.AccessLevelID.ToString(),
                  Text = x.Name
              });


            SelectListItem item = null;
            foreach (SelectListItem a in accessLevelsFromDB)
            {
                if (a.Value == selectedAccessLevelID)
                {

                    item = a;
                    a.Selected = true;
                }
            }

            var accessLevels = new SelectList(accessLevelsFromDB, item.Value);
            return accessLevels;
        }

And also tried returning accessLevelsFromDB:

return accessLevelsFromDB;

View:

@Html.DropDownList("Accesslevels", user.AccessLevelsWithSelectedItem, new { @class = "form-control", @name = "accessLevels"})

Have I used, SelectList Constructor (IEnumerable, Object), correctly? Or what else am I missing? I have tried to google but still don't understand what I'm doing wrong. I Looked at this question SelectList Selected Value Issue - Stack Overflow but that doesn't seem to work.

Update:

this is the model:

public class EditCustomerViewModel
{
    public Customer Customer { get; set; }
    public int CustomerID { get; set; }
    public List<User> Users { get; set; }
    public List<UserToView> UsersToView { get; set; }
    public IEnumerable<SelectListItem> AccessLevelListForSelectedUser { get; set; }

}

Update 2:

I've got it working now and have updated my model and repository.

Model:

public class EditCustomerViewModel
    {
        public Customer Customer { get; set; }
        public int CustomerID { get; set; }
        public List<UserToView> UsersToView { get; set; }

    }

Repository:

public IEnumerable<SelectListItem> GetSelectListAccessLevelsWithSelectedItem(string selectedAccessLevelID)
{
    IEnumerable<SelectListItem> accessLevelsFromDB = DB.AccessLevels
      .Select(x => new SelectListItem
      {
          Value = x.AccessLevelID.ToString(),
          Text = x.Name,
          Selected = x.AccessLevelID.ToString() == selectedAccessLevelID

      });
    return accessLevelsFromDB;
}
Community
  • 1
  • 1
  • Your view model does not have a property named `Accesslevels` so you not even binding to anything. And you do not set the `Selected` property of `SelectListItem` when binding to a property (its the value of the property which determines what is selected (internally the method builds its own SelectList). And `var accessLevels = new SelectList(accessLevelsFromDB, item.Value);` makes no sense because `accessLevelsFromDB` is already a `SelectList` –  Oct 18 '16 at 21:23
  • And view models should never contain data models when editing –  Oct 18 '16 at 21:27
  • AccessLevelsWithSelectedItem is a property of each user in the propety UsersToView in the model and it is this property I'm trying to bind to. Should I put "AccessLevelsWithSelectedItem" as the first string argument of the dropdownlist or did I missunderstand? – user3215947 Oct 19 '16 at 08:03
  • Yes, But even that would not bind if your generating this is a loop. And the answer you have accepted is totally misleading. The `Selected` property is ignored by the `DropDownList()` method unless your not binding to a property - and in your case your not (it will not bind to your model when you submit). And I recommend you read [MVC5 Razor html.dropdownlistfor set selected when value is in array](http://stackoverflow.com/questions/37407811/mvc5-razor-html-dropdownlistfor-set-selected-when-value-is-in-array/37411482#37411482) –  Oct 19 '16 at 08:45

3 Answers3

0

It would be helpful if we could see the model your view is using. Regardless, you're making this far too difficult.

First, DropDownList needs only IEnumerable<SelectListItem>. Razor will take care of creating a SelectList instance and binding the appropriate selected value. In fact, it does that anyways, which is why your own attempts at selecting an item will be fruitless until you find what's causing the wrong or no value to be bound.

In that regard, everything revolves around ModelState, which is composed of values from Request, ViewBag/ViewData, and finally Model. That "finally" part is important, because anything in the request or view data will always override anything set on your model.

In other words, if your action has a parameter like accessLevels or you're setting something in something like ViewBag.AccessLevels. Those values will be used as the "selected" value for the dropdown.

Again, seeing the view model would be helpful here, but generally speaking, you should be using the *For family of helpers in conjunction with a view model. Ideally, you should have a property on your model like AccessLevels, and then do something like:

@Html.DropDownListFor(m => m.AccessLevels, Model.AccessLevelOptions)

Where AccessLevelOptions would be IEnumerable<SelectListItem> and contain the available access levels. With that, you'll never have any issues with the selected value, because Razor will handle everything and you're strongly bound to a particular property on your model. It's only when you start playing with string names, with no real ties to anything that things start to go awry.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • I updated with model. But if I use this @Html.DropDownListFor(m => m.AccessLevels, Model.AccessLevelOptions) how does the dropdown "know" which value to select? I need to select a specific value which is in the model under Model.UsersToView.UserToView.AccessLevel. – user3215947 Oct 18 '16 at 15:19
  • That's what you should be binding to then. It "knows" based on what's in `ModelState`, so you need to compose your model such that the property you're binding to holds the value it has or should have. – Chris Pratt Oct 18 '16 at 15:57
0

This should give you the selected item for your dropdown:

public IEnumerable<SelectListItem> AccessLevelsWithSelectedItem(string selectedAccessLevelID)
    {
        return DB.AccessLevels
          .Select(x => new SelectListItem
          {
              Value = x.AccessLevelID.ToString(),
              Text = x.Name,
              Selected = x.AccessLevelID.ToString() == selectedAccessLevelID
          });
    }
Papa Burgundy
  • 6,397
  • 6
  • 42
  • 48
-1

You can just pass in a value attribute of a hardcoded string or the model value for that property:

@Html.DropDownList("Accesslevels", user.AccessLevelsWithSelectedItem, new { @class = "form-control", @name = "accessLevels", Value = "something" })

or

@Html.DropDownList("Accesslevels", user.AccessLevelsWithSelectedItem, new { @class = "form-control", @name = "accessLevels", Value = Model.MyProperty })
Rob C
  • 818
  • 1
  • 12
  • 26
  • 1
    The `value` attribute should not be messed with. At the best, you're glossing over a deeper problem. At the worst, you'll interfere with proper value binding. – Chris Pratt Oct 18 '16 at 14:57
  • I tried it but it still didn't change selected value for the dropdownlist – user3215947 Oct 18 '16 at 15:03