urlreader
urlreader

Reputation: 6605

Set Preselection for ListBox in ASP.Net MVC4?

In the view, I have

<div class="form-group">
    <div>
        @Html.LabelFor(m => m.DoctorList, new { @class = "control-label" })
    </div>
    <div>
        @Html.ListBoxFor(m => m.DoctorList, new MultiSelectList((List<SelectListItem>)ViewBag.DoctorList, "Value", "Text", ((List<string>)(ViewBag.DoctorsSelected)).ToArray()), new {style="display:block;height:20.0em;", @class = "form-control", Multiple = "multiple"})

    </div>
</div>

DoctorList is a list in model, ViewBag.DoctorList is the entire list of doctors, they are something similar to:

public static List<SelectListItem> GetDoctorList()
{
    List<SelectListItem> ret = new List<SelectListItem>();

    // load doctors from database
    // for now, fake data
    for (int k = 1; k <= 30; k++)
    {
        string n = "Doctor" + k.ToString();
        ret.Add(new SelectListItem() { Value = n, Text = n });
    }
    return ret;
}

ViewBag.DoctorsSelected is a List, which is a list of doctor names, something similar to:

List<string> doctorsSelected = new List<string>();
doctorsSelected.Add("Doctor1");
doctorsSelected.Add("Doctor5");

What I want to do is that preselect the doctors in the listbox. However, it always shows the listbox, but no reselection.

I also tried to use below in GetDoctorList()

ret.Add(new SelectListItem() { Value = n, Text = n, Select = true });

Still no preselection.

Anyone knows how to do it? I'm using MVC4.

Thanks

Upvotes: 0

Views: 563

Answers (1)

user3559349
user3559349

Reputation:

You cannot use the same name for the property your binding to and the SelectList. Your model should have a property (say)

public IEnumerable<string> SelectedDoctors { get; set; }

and the view will be

@Html.ListBoxFor(m => m.SelectedDoctors, (IEnumerable<SelectListItem>)ViewBag.DoctorList)

If SelectedDoctors contains values that match the values in the SelectList, then those items will be selected when the view is rendered. For example in the controller,

model.SelectedDoctors = new List<string> { "Doctor1", "Doctor5" };
return View(model);

Note also that ViewBag.DoctorList is already IEnumerable<SelectListItem> so its just pointless extra overhead to create an identical new IEnumerable<SelectListItem> from it using new SelectList() in your view.

Edit (in response to OP query as to why the names must be different)

The way the ListBoxFor() works is

  1. Get the value of the property your binding to from the ViewDataDictionary (in your case the item in the ViewDataDictionary is List<SelectListItem>).
  2. Build a new IEnumerable<SelectListItem> from the SelectList provided in the second parameter (in order to set the Selected property of each SelectListItem based on the values your binding to).
  3. Generate the html for each <option> element based on the Value, Text and Selected properties of each SelectListItem.

In your case, as each SelectListItem is created, its checks if any values in the property your binding to match the Value property of the SelectList, but your values are "System.Web.Mvc.SelectListItem" (they are complex objects so the .ToString() value of the object is used) and none of your SelectListItems have a value of "System.Web.Mvc.SelectListItem" (just "Doctor1", "Doctor2" etc.) so the Selected property is false and consequently, none of the <option> elements have the selected="selected" attribute set.

The above is a simplified explanation and if your want to see how it all works, you can view/download the source code here.

Upvotes: 2

Related Questions