I have a main view with a model AViewModel:
public class AViewModel
{
public int P1 { get; set; }
public BViewModel P2 { get; set; }
}
I have a partial view with BViewModel:
public class BViewModel
{
public string P1 { get; set; }
public string P2 { get; set; }
}
From the main view I render the partial view as the following.
await Html.RenderPartialAsync("~/Views/_B.cshtml", Model.P2);
On the main view, on submit ([HttpPost] Index controller method), I'm expecting the AViewModel.P2 to be populated with the BViewModel coming from the partial view, but it's not. What am I doing wrong? Is there a way to populate the original property (namely AViewModel.P2) with information collected from the partial view?
In other words, the problem is that on the controller method, model.P2.P1 and model.P2.P2 are null
Related
I have 3 models. 1 model am using for the search box rest 2 I am using for display the checkbox list.
for search box I don't want Ienumerable type model but for checkbox I want Ienumerable type model
Data is coming from different controller
How can I do this in a single view?
Please give some example.
Make ViewModel then send your ViewModel to view after setting properties;
public class MyModel1 {}
public class MyModel2 {}
public class ViewModel
{
public MyModel1 MyModel1 {get; set;}
public MyModel2 MyModel2 {get; set;}
}
Then in your view after setting #model ViewModel
you can use any sub models you want like #Model.MyModel1 etc
If you want to use 3 models in a view, you have to declare a "Bag" view model where you wrap all submodels that you want to use.
First, if you must create your submodels, if you haven't then you include them in the bag view model.
public class FirstViewModel
{
public int MyProperty { get; set; }
}
public class SecondViewModel
{
public string MySecondProperty { get; set; }
}
public class ThirdViewModel
{
public DateTime MyThirdProperty { get; set; }
}
public class BagViewModel
{
public FirstViewModel FirstModel { get; set; }
public SecondViewModel SecondModel { get; set; }
public ThirdViewModel ThirdModel{ get; set; }
}
The submodels can be either view or binding models.
And in your razor view, you include the BagViewModel:
#model BagViewModel
Then if you want to use FirstViewModel ( for example ), you do it with:
#Model.FirstViewModel
I really can't get my head around how to use ViewModel's in MVC. Say I have two simple domain models:
public class Customer
{
public int Id { get; set; }
public string CustomerName { get; set; }
}
public class Order
{
public int Id { get; set; }
public string ProductName { get; set; }
}
And now my goal would be to create a ViewModel that displays (combines) the CustomerName and ProductName to display to a view. I'm confused what to include in the ViewModel to accomplish this. Do I use the same property names as my domain models like so?
public class MyViewModel
{
public string CustomerName { get; set; }
public string ProductName { get; set; }
}
How does the ViewModel know that the properties come from two different classes? Or am I forming my ViewModel incorrectly?
As i can see it you have a bigger design problem here.
Lets say you need to show on the UI only the CustomerName and ProductName. Well then just add those two on to your ViewModel class and you`re good to go, exactly how you described it.
public class MyViewModel
{
public string CustomerName { get; set; }
public string ProductName { get; set; }
}
Getting the data in two variables is not a problem:
Customer customer = service.GetCustomer();
Product product = service.GetProduct()
And now that you have everything you need you can just set the data and pass it to the view.
MyViewModel viewModel = new MyViewModel();
viewModel.CustomerName = customer.CustomerName;
viewModel.ProductName = product.ProductName;
It always depends on what you need to show on the UI and only send what you need and nothing more.
You do not need to have exactly one Model that you pass all over the place in your application, Business, DataAccess, UI. You can have something custom if you really need it.
You would have to set this up yourself in the ViewModel, as a template it could look something like:
public class MyViewModel
{
public string CustomerName { get; set; }
public string ProductName { get; set; }
public void GetCustomerName(int customerId)
{
CustomerName = CustomerServiceLayer.GetCustomerName(customerId);
// CustomerService Layer (I.e. a repository that contains this info;
}
public void GetProductName(int productId)
{
ProductName = ProductServiceLayer.GetProductName(productId);
// ProductService Layer (I.e. a repository that contains this info;
}
}
You would then have two other Service Layers (ProductServiceLayer and CustomerServiceLayer) that speak to the database/repository to obtain the information you want. That information is then returned to the view (via your ViewModel) and displayed to the user.
Alternatively you could pass a Customer and a Product object directly into your ViewModel (via a constructor).
public class MyViewModel
{
public Customer MyCustomer { get; set; }
public Product MyProduct { get; set; }
public MyViewModel(ICustomer customer, IProduct product)
{
MyCustomer = customer;
MyProduct = product;
}
}
The downfall here would be that you expose your entire Customer and Product classes in the View.
You can do it like that but you generally build the viewmodel up on render in the get action and then post parts of that view model back and handle it on a post action. The MVC binding does the magic once getting the values posted back from a form.
I wouldn't put business logic inside the viewmodel but rather build the viewmodel up in your controller using managers/services.
You could also make it so the viewmodel has your complex model types as the properties like so..
public class MyViewModel
{
public Customer Customer { get; set; }
public Product Product { get; set; }
}
ViewModel rapresents a model you use to go to your view. In your controller you'll retrieve data and pass them to your ViewModel.
Imagine you have a checkbox in you view that rapresent a Gold Customer: it's not suitable to change your domain model to add this information and it's not a good practice to make your code dirty with Viewbag and Viewdata (imho).
So you create a model or template that has all the information you need. In our case:
public class MyViewModel
{
public string CustomerName { get; set; }
public string ProductName { get; set; }
public boolean IsGoldCustomer { get; set; }
}
Ofter you'll have to convert your model into a ViewModel and viceversa in order to pass data from a "DOMAIN model" to a "VIEW model".
edit - just rewording the question
If I have countries>states>cities
In my country controller, I fill a viewmodel with the country useing id, along with its states.
In the view, I can then say "for each state, show population".
What i don't understand, is how to also say, in the same view, "for each state, show each city".
Is everything in the same view model? Am I supposed to use nested partial views? How do I pass models from country view to state partial view to city partial view?
end edit
I have data organized in a parent>child>child>child fashion
Here are my viewmodel entities
public country country { get; set; }
public IList<state> states { get; set; }
public IList<city> cities { get; set; }
Here is my view
#model myproject.viewModel.vwcountry
#for (var c = 0; c < Model.country.states.Count(); c++)
{
#Html.Partial("_states", Model.states[c]);
}
And the first partial view model
#model myModel.state
//partial view displays stuff from model
This all was working fine.
Now, I want to add the children of state. This is where I'm lost.
I feel that I should be passing the view model instead of the state model, but that won't even compile.
I feel there should be a seperate view model like this...
public state state { get; set; }
public IList<cities> cities { get; set; }
But this view model can't be made available to the view becuase in the current context, it doesn't exist.
I imagine this is a common pattern, but I haven't found a similar example...
your model is not correct. here is the correct model:
public class vwcountry
{
public country country { get; set; }
public IList<state> states { get; set; }
}
public class state
{
public state state { get; set; }
public IList<city> cities { get; set; }
}
I began to create my controller for the parent model listed below. I am using view models for all my views, but before I got around to adding the logic for the Create (Post) action I just hit submit for the hell of it thinking my viewmodel would not map to my model.
To my surprise it actually worked. I am using AutoMapper and have set up all the mappings for the child models to their corresponding models, but not the parent model (as absent in the post result). What is going on here that MVC has allowed such magic to happen?
Model:
public partial class ParentModel
{
public int Id { get; set; }
public int Child1Id { get; set; }
public int Child2Id { get; set; }
public int Child3Id { get; set; }
public int Child4Id { get; set; }
//other data
public virtual Child1 Child1 { get; set; }
public virtual Child2 Child2 { get; set; }
public virtual Child3 Child3 { get; set; }
public virtual Child4 Child4 { get; set; }
}
View Model:
public class ParentCreateViewModel
{
//other data
public Child1ViewModel Child1 { get; set; }
public Child2ViewModel Child2 { get; set; }
public Child3ViewModel Child3 { get; set; }
public Child4ViewModel Child4 { get; set; }
}
View (Create.cshtml):
#model Project.ViewModels.ParentCreateViewModel
#*EditorTemplates and such*#
Controller (Get):
public ActionResult Create()
{
//some list logic
return View();
}
Controller (Post - I haven't yet changed it to the ParentCreateViewModel or AutoMapped it back to ParentModel):
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ParentModel parentModel)
{
if (ModelState.IsValid)
{
db.ParentModels.Add(parentModel);
db.SaveChanges();
return RedirectToAction("Index");
}
//some list logic
return View(parentModel);
}
My parent model and all child models are persisted correctly to the database. Does MVC do some kind of behind the scene binding? Shouldn't it be expecting a ParentCreateViewModel?
The default model binder binds on name of elements. Since both models would share these properties (and therefore, HTML element names when using editor templates and HTML helpers), it will bind it to the model.
Both of your models will generate form elements like this:
<input type="text" name="Child1_Name" />
..etc. When the form values are posted, the model binder inspects and finds "Child1_Name". The underscore signifies a child class property. So, it doesn't matter which model you choose because Child1.Name is a valid property of both models. So, since you've told the action method you want a ParentModel, the model binder happily applies the value to the Child1.Name property when it's found.
I have a List collection in my strongly typed viewdata.
How do I use the Html.DropDownList helper?
<%= Html.DropDownList(ViewData.Model.Cars) %>
(the above doesn't work, doesn't seem to match any of the signatures)
This is MVC2.
If your Car class looked something like this
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
}
And you put a property on your view model like this
public int CarId { get; set; }
Your resulting view model would look like this
public class YourViewModel
{
public int CarId { get; set; }
public List<Car> Cars { get; set; }
}
You could do this
this.Html.DropDownListFor(x => x.CarId, new SelectList(this.Model.Cars, "Id", "Name"))
When posted, CarId would get get bound to the bound by the default model binder if the view model was a parameter to the Action.