I’m building one page to edit various product types. Each product type has a view model (TentProductVM, BootProductVM) that inherits from ProductVM. My MVC2 View checks the model type and adds fields as appropriate. For example, if the model is of type BootProductVM I call Html.TextBoxFor to add a field for the boot’s foot size. Page displays fine.
The problem is the post. I’ve declared a function (in VB) as follows:
<HttpPost()>Function Edit(byval prod as ProductVM) As ActionResult
Of course, this function only receives the form data from the base class ProductVM. So instead I added a function for each product type:
<HttpPost()>Function EditTent(byval prod as TentProductVM) As ActionResult
<HttpPost()>Function EditBoot(byval prod as BootProductVM) As ActionResult
and point the View to the appropriate post function:
Using Html.BeginForm("Edit" & Model.ObjectTypeName, "Catalog")
However, when EditTent or EditBoot gets called, the prod parameter only contains data from the base class. All the fields declared in the subclass view models are left at default values.
What am I doing wrong? Or is there a better approach? (The obvious solution is multiple pages but, since ProductVM has many fields relative to the subclasses, I’d rather not.)
After much experimentation, I’ve decided not to use this approach. First, I couldn’t get it to work without resorting to having an Action parameter of type FormCollection. Second, the obvious solution I discarded is appealing if I use a partial view. The partial view has all the fields associated with the base class (ProductVM), leaving only the fields associated with the derived classes (TentProductVM, BootProductVM) in the regular views.
Felt like I was fighting against the MVC auto-magic, which is never the right approach.
The thing to remember about MVC is that it’s based on the “Convention over Configuration” mindset. So if you’re passing a strongly typed class class instance to your action method, it expects it to be named “model”.
Try changing your declarations to look like this:
The other (less ideal) option would be to expect a FormCollection object in your action method.
Update
Just updating to include some of the discussion points below… In order to post a strongly typed object to a controller action method, the types need to match up.
Assuming your controller’s action method looks like this:
Your view should be typed accordingly: