views:

64

answers:

1

I'm passing data between my controller and my view using a ViewModel class. When there are validation errors, I return the ViewModel back to the view so the user can see the errors.

I'm having trouble figuring out the best way to deal with the data that is only passed from the controller to the view, which isn't passed back to the controller, such as the contents of dropdown lists.

Here's a simplified example from the project I'm working on:

I have a Widget object in my domain model that has an Employee property. I have a view that allows the user to edit this employee property by selecting their name from a drop down list.

public class WidgetFormViewModel {
    // Used for a drop down list in the view
    public SelectList EmployeeList { get; set; }
    // This will contain the employee the user selected from the list
    public int EmployeeID { get; set; }      
    public Widget Widget { get; set; }
}

And the controller:

// GET: /Widget/Edit/1
public ActionResult Edit(int id) {
    var widget = _widgetService.GetWidgetByID(id);
    var employees = _widgetService.GetAllEmployees();

    var viewModel = new WidgetFormViewModel()
                    {
                        EmployeeList =
                            new SelectList(employees, "ID", "Name", widget.Employee),
                        Widget = widget,
                        WidgetID = widget.ID
                    };
    return View("Edit", viewModel);
}

// POST: /Widget/Edit
public ActionResult Edit(WidgetFormViewModel viewModel) {

    var existingWidget = _widgetService.GetWidgetByWidgetID(viewModel.WidgetID);
    existingWidget.Employee = _widgetService.GetEmployeeByID(viewModel.EmployeeID);

    // try { /* Save widget to DB */ } catch { /* Validation errors */ }

    return ModelState.IsValid
           // Update was successful
           ? (ActionResult) RedirectToAction("List")
           // Model state is invalid, send the viewModel back to the view
           : View("Edit", viewModel)                 
}

Now, here's the problem: When the ModelState is invalid and viewModel gets passed back to the view, its EmployeeList property is blank. What is the best way to deal with this?

Should I just repopulate it before returning to the view? This method seems difficult to maintain. (What if I add PageTitle and HeaderText to the view model as well? Suddenly there are more things to keep track of.) Is there another approach?

+1  A: 

Inside of the catch block of the controller action handling the post, extract your error messages and add it to this.ModelState, then have it return this.Edit(viewModel.widgetID);.

You already have all the logic you need built up to display the view appropriately, you just want to use ModelState to make sure that errors make it back to the view.

48klocs