I have a View to create an object and this object can be of three types. So I decided to create a tab panel with 3 tabs, and each tab represents a type of this object.
The user must choose which tab they will fill the data and press the submit. By the way, each tab has a FORM and a submit.
Until now, 1 View and 3 forms.
I want to know if there is a better approach to do that. Using render actions, partials, only one viewmodel, a lot of viewmodels.
My last try is using a big view model with all possibilities and a hidden field for determinate the type/tab panel is filled. When the user submit, I get only the fields this object type will use and save in the database.
Pro: Only one view model, only one controller. If the modelstate has errors, I can show the result in view with no much effort (using html validationmessagefor). Razor binds and Razor helpers. Cons: I can't use dataannotations in all fields because some fields era required for a type and not for the other one and they have the same name. If a field of one form is changed, the field in another tab/form with the same name will change too. The object has a few properties that must change by the type choose, but another ones which is the same. Those ones show changes his value and the validation messages shows for every form. This is the best approach
EDIT
I'm thinking about create a viewmodel as a container for the 3 viewmodels. So the fields will be separated and for each "submit" I'll use one of the three viewmodels.
Its a good approach?
Whether you use child actions, partials or just throw everything in one view makes no difference. In particular, once you've posted, whether you used child actions or partials to render the form in the first place, is inconsequential. You can't post to a child action.
I would suggest, first, that you create a wrapper view model to hold all your form-specific view models and use one view model per form on the page, and don't forget to instantiate those view models (the constructor of the main view model is a good place):
public class MainViewModel
{
public MainViewModel()
{
Form1 = new Form1ViewModel();
Form2 = new Form2ViewModel();
...
}
public Form1ViewModel Form1 { get; set; }
public Form2ViewModel Form2 { get; set; }
...
}
Next, since you are actually using separate submit buttons for each form, it makes this even easier, as you can just give a name to each submit button, and use that to determine which form the user submitted:
<button type="submit" name="_form1Submit">Submit</button>
And, then, in your action:
if (Request.Unvalidated["_form1Submit"] != null)
{
// form 1 was submitted
}
Finally, by default, the modelbinder will validate your entire view model (MainViewModel
), and you'll get errors on any fields on the other forms that weren't filled out. However, you can use TryUpdateModel
to re-run the model validation on whatever part of it you want:
if (Request.Unvalidated["_form1Submit"] != null)
{
TryUpdateModel(model.Form1);
if (ModelState.IsValid)
{
// do something interesting
}
}