Justin Saraceno
Justin Saraceno

Reputation: 2516

MVC3 DropDownListFor not selecting saved value

I'm displaying a list of users. Each user record has a TrainingEvent object property (from a choice of many TrainingEvents). I've created a viewmodel to include the User list and the TrainingEvents list.

ViewModel:

public class RegistrationViewModel
{
  public IEnumerable<Domain.Entities.User> Users { get; set; }
  public IEnumerable<SelectListItem> TrainingEvents { get; set; }
}

(note: the Domain.Entities.User contains a TrainingEvent object property)

Controller:

public ActionResult Dealership(int id)
{
  var model = new RegistrationViewModel
    {
      Users = repository.Find
             .Where(u => u.Dealer.DealerId == id).OrderBy(u => u.LastName),
                 TrainingEvents = repository.TrainingEvents.ToList()
                                  .Select(x => new SelectListItem
                                          {
                                            Text = x.Date.ToString() + " - " + x.LocationName,
                                            Value = x.TrainingEventId.ToString()
                                          })
    };

  return View("East", model);
}

Binding in View:

@foreach(Company.Domain.Entities.User usr in Model.Users)
  {
     <tr>
         <td>@usr.LastName</td>
         <td>@usr.FirstName</td>
         <td>@usr.JobDescription</td>
         <td>@Html.DropDownListFor(m => m.Users.FirstOrDefault(u => u.UserId == usr.UserId).TrainingEvent, Model.TrainingEvents)</td>
     </tr>
}

The users are listed and each user row has a dropdown which populates with TrainingEvents. However, the value previously saved in the user's TrainingEvent object isn't selected. Any ideas as why not?

Upvotes: 0

Views: 284

Answers (1)

Darin Dimitrov
Darin Dimitrov

Reputation: 1038770

You are incorrectly using the DropDownListFor helper. This helper expects to be passed as first argument a simple lambda expression containing at most a member access. In your example you are attempting to construct some complex lambda expression using things like FirstOrDefault extension methods which is not supported. Also it is not the responsibility of the view to be fetching some data from the model. It's the responsibility of the controller to populate a suitable view model for the view and pass it for consumption

So I would recommend you to use a real view model reflecting the requirements of your view:

public class UserViewModel
{
    public int TrainingEventId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string JobDescription { get; set; }
}

public class RegistrationViewModel
{
    public IList<UserViewModel> Users { get; set; }
    public IEnumerable<SelectListItem> TrainingEvents { get; set; }
}

which will be populated in your controller action:

public ActionResult Dealership(int id)
{
    var users = repository
        .Find
        .Where(u => u.Dealer.DealerId == id)
        .OrderBy(u => u.LastName)
        .Select(u => new UserViewModel
        {
            TrainingEventId = u.TrainingEvent.TrainingEventId,
            FirstName = u.FirstName,
            LastName = u.LastName,
            JobDescription = u.JobDescription
        })
        .ToList();

    var trainingEvents = repository
        .TrainingEvents
        .ToList()
        .Select(x => new SelectListItem
        {
            Text = x.Date.ToString() + " - " + x.LocationName,
            Value = x.TrainingEventId.ToString()
        });

    var model = new RegistrationViewModel
    {
        TrainingEventIds = TrainingEventIds,
        TrainingEvents = trainingEvents
    };

    return View("East", model);
}

and finally in your view bind the DropDownListFor helper to the corresponding value in the view model:

@for(var i = 0 ; i < Model.TrainingEventIds; i++)
{
    <tr>
        <td>@Html.DisplayFor(m => m.Users[i].LastName)</td>
        <td>@Html.DisplayFor(m => m.Users[i].FirstName)</td>
        <td>@Html.DisplayFor(m => m.Users[i].JobDescription)</td>
        <td>
            @Html.DropDownListFor(
                m => m.Users[i].TrainingEventId, 
                Model.TrainingEvents
            )
        </td>
    </tr>
}

Upvotes: 3

Related Questions