views:

827

answers:

1

I'm having a hard time getting a fairly simple binding to work.

When editing an employee I want to display a listbox containing all the available roles in the system, (the employee's roles selected), and when saving the employee I want the selected roles to get populated by MVC into the Employee object which comes as an input param to the controller.

I know I can read the comma-separated values from Request.Form, but I'd rather not touch the Request object directly in my controllers as this makes them harder to test.

What is the best way to get MVC to supply me with the list of roles as an input param?

+1  A: 

You have two options. The first is to get the values in the controller and put them into the ViewData dictionary, like so:

var list = EmployeeRoles.GetAll();
ViewData["EmployeeRoles"] = list;

Then you access it in the View using:

<%= (List<EmployeeRoles>)ViewData["EmployeeRoles"] %>

This way is kind of ugly because the view then has to know that it can use a 'magic string' to get an object out of the ViewData dictionary, which then has to be casted back into its original type.

The second way is more elegant, but introduces a little more complexity into your code. You create a ViewModel class, or basically a class that encapsulates all the data you want:

public class EmployeeViewModel
{
    public Employee Employee { get; set; }
    public ICollection<EmployeeRoles> EmployeeRoles { get; set; }

    public EmployeeViewModel(Employee employee, ICollection<EmployeeRoles> roles)
    {
        Employee = employee;
        EmployeeRoles = roles;
    }
}

Then you would pass it from the controller to the view like so:

return View(new EmployeeViewModel (employee, roles);

On the view side, you'd access it like any other model:

<%= Model.Employee.Name %>
<%= Model.EmployeeRoles.First() %>

This method is more testable, but then you'd have to make a new ViewModel class for anything that requires data from more than one source.

As for returning the data from the view to the controller, the default model binder is actually quite good. You just have to use a HtmlHelper on the View to let it know what it should send the value back as. I don't have my book in front of me right now, but it should be something like this for a textbox:

<% Html.TextBox("Name", Model.Employee.Name) %>

The HtmlHelper will figure out what it needs to send back in order for the model binder to bind it correctly. I don't know what it is for a DropDownBox off the top of my head though.

Daniel T.