In my View i have to put two different Forms and i have to use two different ViewModels. So i decided to use Tuple.
View:
#model Tuple<pi.Models.AddNewMechanic,pi.Models.ExistingUser>
and I got two forms
But how can i recive it from View in HttpPost Controler?
I tried like that:
public ActionResult AddMechanic(Tuple<pi.Models.AddNewMechanic, pi.Models.ExistingUser> model) {}
but i got message it cannot find method with parameter, so how I have to implement it inside this method, but there is a question how?
I strongelly sugest you create a new Model and inside of your new model, you can put this two object. Take care to dont mix domain model and view model. Otherwise, you will have always this kind of problem.
Domain Model
- class a
- class b
View Model
- class AB
prop A, prop B
I suggest you do this by the book, which would be:
AddMechanic.cshtml has no special view model, but contains two partial views. This is your "page with two forms".
_AddNewMechanic.cshtml is the first partial view form, which has AddNewMechanic as view model.
_ExistingUser.cshtml is the second partial view form, which has ExistingUser as view model.
The form in _AddNewMechanic.cshtml posts to the AddNewMechanic action method, which takes an AddNewMechanic as parameter.
The form in _ExistingUser.cshtml posts to the AddExistingMechanic action method, which takes an ExistingUser as parameter.
Upsides:
No need for any Tuple weirdness.
You can keep your existing View Models.
Your action method parameters will not normally be null, so no need for weird null checks.
Easy to follow and understand your code.
Related
I think i know some of the basics of MVC but there's one thing which I don't understand yet.
In the view Create which is generated automatically when you set up your project, how is data sent to the controller? I'm used to seeing ActionLinks with parameters but here there's no actionLink so I can't understand how data travel from the view to the controller.
Could you explain it to me please?
as you know, in your view, the very first line (usually) tells the view, about the Model being used within this view. like:
#model Models.CarViewModel
lets suppose, you have a form on this view, and it is posted to some action called Edit. Then you must have your Edit action, expecting the parameter of type you used as model in your view. like:
[HttpPost]
public ActionResult(CarViewModel model)
{
//logic
}
This convention is known as Strongly Typed View. Suppose Then you have some textbox for a property Name of your model as:
#Html.TextBoxFor(x => x.Name)
when the form is posted to Edit Action, the variable model in parameter of Edit action will be holding the respective values. i.e, model.Name
Please consider I have 2 forms which will put in single view which are student form and teacher form. Each has different form action. I need to pass these 2 models from controller at once. So i decide to take the 2 into a new model class:
Public Class StudentTeacher
Public Student As ClsStudent
Public Teacher As ClsTeacher
End Class
And send the model from the controller:
Return View(New StudentTeacher With {.Student = New ClsStudent, .Teacher = New ClsTeacher })
And in the view I have 2 partial view one for student form and one for teacher form. For the student form would be like this:
#ModelType Model.StudentTeacher
#Using Html.Beginform()
....
#Html.TextBoxFor(Function(m) m.Student.name)
....
End Using
This view works good only the problem is the id for each element will include the model name, so the input for student name will be:
<input id="student.name">
So when the form got submitted, the controller will receive it as model of 'StudentTeacher' instead of 'Student'. What I want for this student form is send the student model only. The teacher can be sent in different form in the same view. Any suggestion to fix this? Thank you very much...!
There are 2 ways I can suggest to fix the problem:
You can use a ViewModel by combaining both of two models in it. Then return this ViewModel from Controller to the View. After changing data on the View then return this ViewModel to the Controller again. If you want to make different action with this data you can make this in the Controller instead of calling different method from the View.
As you did, you can use partial views and then send each model to the related partial views in the main view. However, when you submit the form you should pass the form parameters at one time as two parameters (model I and model II). Then you get the form data in controller (controller accepts these two arguments: model I and model II as well).
I have a view with a form that's is typed to a viewmodel called AddEditItemVM. This viewmodel has the following property:
public List<Category> Categories{get;set;}
What im trying is two things:
Render a checkbox foreach Category in the generic category list of my viewmodel.
Make that when the form is posted receive, in my controller action, the property Categories instantiated (into the instance of AddEditItemVM)
About the first point, i would like to use any helper (if exists) that renders a group of checkboxes using lambda expressions like (m=>m.Categories), instead to render the checkbox with a foreach into the view.
About the second point, i read that there is one feature in MVC called Custom Model Binders. These get values from ValueProviders (querystring, cookies, or Form values) and creates the necessary instances passing it to specific action called after a form was posted. Should i create one custom model binder in order to receive my property Categories instantiated?
This might work
CheckboxList in MVC3.0
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:
<HttpPost()> Function EditTent(byval model as TentProductVM) As ActionResult
<HttpPost()> Function EditBoot(byval model as BootProductVM) As ActionResult
The other (less ideal) option would be to expect a FormCollection object in your action method.
<HttpPost()> Function EditTent(byval form as FormCollection) as ActionResult
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:
<HttpPost()> Function EditTent(byval model as ProductVM) As ActionResult
Your view should be typed accordingly:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Your.Namespace.ProductVM>" %>
So like the title says, I created a view model in my asp.net mvc application so it would be strongly typed to my view. My view model is a combination of two of my model classes. Now when the user hits the save button on that view, it goes to a controller. How does it know what controller to go to? I built my controller 1 - 1 so to speak with my models and views so controller A knows about Model A and controller B knows about Model B. But if I have a view model that is AB how does it know on subit to go to A or B. Do I need a controller called AB Controller?
The controller and action invoked do not depend on the viewmodel object you used to bind the page during initial view rendering. The controller (and action) invoked is determined by the URL of the request sent. (One of the routes you have defined will be matched based on the URL string of the request or a 404 not found error will be returned.)
A submit button in an HTML form (usually a POST) will have an action attribute that determines its url target, an anchor tag will have an href, etc.
In your situation where you have a custom viewmodel object you can define an action to expect and to attempt to parse that specific type of object by specifying it as the parameter to your action:
public ActionResult SaveSystemSetting(SystemAdminVM item) {
An Action Method doesn't receive a model. It receives parameters.
Anyway I think I know where you come from: One of the parameters of your action has the type of the ViewModel used in the View. That is a common layout and makes a lot of sense. In lots of projects it is so widely used that after some time you start to think that an action actually receives a model.
Just remenber that the parameters of your action can by anything that can by filled by the ModelBinder. You could pass both Models as parameters, you could pass a ViewModel that agregates Model a and b or you could pass a ViewModel that has properties of a + b.
Agregation ist the most common approach.
Generally we overload our action methods in the controller so if you have an action called edit that renders the view with your viewmodel object, you will have an overloaded edit action method with the HttpPost specified for that method.
The data to this method will be passed as form value collection values or you can bind it to your viewmodel object if you like and process it further.