I'm trying to create a view that will create a subcategory.
In order to create this view I inherit my model for subcategories in the view in order to access the required attributes etc.
Now one of the attributes I wish to set on my subcategory object is a reference to a normal Category.
However I am not sure how to populate my dropdownlist with category items since I am already using the model of subcategories.
My question is, what would be the best way to access a SelectList of category objects in my subcategory view.
I've considered using partial views or perhaps transfering the data in my ViewBag or ViewData.
What would be the best way to do this?
You need to use a ViewModel. This is basically a class that you use to bring together all the pieces of the various models required for your view.
It might look something like:
public class CategoryListingsVieWModel
{
public IList<ISubCategory> Subcategories{get;set;}
public IList<ICategory> Categories{get;set;}
[...] // Any other data your view needs
}
This then becomes the model for your view which your pass from your controller.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I have a List<MyModel> that I am returning from controller to view
Shall I create a new class to hold this List and return object of the new class or I can return the List itself..
which one is a better programming practice ??
It depends on what your exact requirements are, consider the below two scenarios.
Using MVC webapi with any js framework like angular/jquery or returning partial view.
You just want to bind the list to a grid and that grid will be updated with new data from same controller action. In this scenario its better to return the list instead of view model, this will ensure that only required data is sent back to view.
``
[HttpPost]
public List<string> Index(string txtJsonIn)
{
return new List<string>();
}
Using MVC without any js/ajax calls
In this case the view will be loaded with values from ViewModel everytime, so if you just keep the List as your return value from action, it will be hard to add new property in future.
class MyViewModel
{
List<string> MyList { get; set; } //Your list that you need right now
string PropertyThatCanBeAddedInFuture { get; set; }
}
[HttpPost]
public MyViewModel Index(string txtJsonIn)
{
return new MyViewModel();
}
You can write the view as below
#foreach (string str in Model.MyList)
{
<tr>#str</tr>
}
Also using viewModels is always a good way to have loose coupled code, don't directly use any model from database, instead use Automapper to map your viewmodel to models from database.
In a partial view I have often used an IEnumerable where there is repeating logic
#model IEnumerable<Result>
#foreach (Result res in Model)
{
<div data-id="#res.ID">
<p>
<!-- Code goes here -->
</p>
</div>
}
View-model is just a conceptual term in MVC's presentation layer. Technically it's just a concrete class.
So real question here whether to use View-model/class or directly pass List.
Now back to the point - Wrapping 'only' list in another class will yield nothing unless you have few other members to be wrapped and passed to view. If there's something more than a List that your view needs, create a class (call it View-model in MVC) to wrap all that stuff and pass it to view.
There is really no reason to create a view model other than personal preference if you just have that one property UNLESS there is any chance that you will be adding more properties in the future.
However it is best practice to utilize interfaces whenever possible to keep your code decoupled. That said you should switch it to IEnumerable instead of list.
I always create a viewmodel, to pass data to my view, populate it in your controller and then pass it to your view. This is a clean way of working in MVC.
TIP : Make a new folder ViewModels in your Models folder.
The same way with Entities, never directly use your entities , use viewmodels that provide just the things you need in your views. Also take a look at Data Annotations , these can come in handy when using a viewmodel for form validation etc...
you can just create a viewmodel like Jelman said and in it just declare a list of your model like this by creating another class file in your model folder that is going to contain your list of model
namespace projectname.Models
{
public class ModelNameViewModel
{
public List<ListOfModel> { get; set; }
}
}
or you could simply Change the declaration on the top of your view to have a list of your model like this if there is no other field you need to add to the model
#model List<YourModelName>
While you can return that model to the view, chances are that not all data will be used in the view. Therefore we create view model classes which only hold data relevant to the view and we use a mapper (take a look at AutoMapper) to map between the two objects.
While this adds another class to manage, it keeps the domain model nice and clean and without any "view specific" properties (such as lists used in drop-downs etc.)
What you end up returning will end up being whatever you need in the view, as you might want to have some other data (or metadata) with that collection, in which case an object wrapper will be used.
Hope this helps.
It is more correct to create a new model containing a list. If tomorrow you need to add a new property, you can easily add it to this model without changing viewmodel in your view.
Compare:
You have a model with a list of objects:
class MyModel
{
public List<int> Comments {get;set;}
}
Your view looks like this:
#model MyModel
foreach(var comment in Model.Comments)
...
and when you need to add new property, you an easily do this:
class MyModel
{
public string Title {get;set;}
public List<int> Comments {get;set;}
}
your view will looks like
#model MyModel
...
Model.Title
...
foreach(var comment in Model.Comments)
...
So you do not need to change the model type in the controller and in the view, you simply add new properties to the created model
I use a MVC project written with C#.
I've an object 'Recipe' that contains :
int id;
List<Ingredient> ingredientList;
String description;
//and so on
When I pass a 'Recipe' object from my controller to my view, the ingredient list contains well the different ingredients of my recipe. In my view, to save the ingredient list, I do this :
#Html.HiddenFor(model=>model.Ingredients)
But when I submit my form in my view, so It is going to my controller. And when I use the debugger to see what contains the current recipe, I notice that my ingredient list is empty. I don't know why.
Do you have a solution ?
The problem here is that the view only knows how to do a HiddenFor for basic types.
You could work around this with something like:
#foreach (var item in Model.Ingredients)
{
#Html.HiddenFor(modelItem=>item.IngredientProperty1);
#Html.HiddenFor(modelItem=>item.IngredientProperty2);
//and so on for all the properties of your Ingredient class
}
With that said, you might be better advised to make a view model with only the properties you intend to edit as read/write properties of the class. You would then not be passing all the extra data around in http POST that wasnt needed.
I've come across an interesting question during my development. Right now, I use a database-agnostic unit of work layer to abstract the access of data from the actual database dependencies in my ASP MVC 4 web application.
Each individual database project which implements the unit of work interfaces are aware of my business models (models that go directly to/from the database). I'm not too sure how I feel about this approach, but that's not the question I am going to ask.
Should I be using a solution like AutoMapper to convert my business models to/from domain models - models that are passed to the view and used for any work that shouldn't have access to database fields (i.e., IDs)?
For example, consider inside my BusinessModels project, I have the following classes
BusinessModels
/UserAccounts/
User.cs
- ID
- Username
- HashedPassword
- Salt
UserSettings.cs
- IsSubscribedToNewsletter
- AllowDirectEmails
Would it make any sense to bind these User, and UserSettings models into a single model using AutoMapper like so
MyProject
/DomainModels/
User.cs
- Username
- HashedPassword
- Salt
- IsSubscribedToNewsletter
- AllowDirectEmails
for the purpose of views?
This question also extends to non-MVC projects but I feel seeing as I am working on an MVC project it would make more sense to ask it in that tag.
TLDR is there any point in mapping business models/entities to view models or does that provide an unnecessary layer of abstraction? And if so, would the Repositories contain business models, or view models (which map automatically to business models under-the-hood)?
You can use view models for two different things:
rendering a new view (GET action), passing the view model object as the model for the view
receiving data back from the view, in a Post Action (POST action), using the view model as parameter
(I know, the second is arguable. But it's not strange to use the view models for this)
The model for the GET action needs all the properties neccessary to render the View:
the values of the entity you're showing/editing
extra values needed to render the view (for example SelectLists for drop down lists)
Suppose that you have a User which can belong to one UserGroup.
In this case, if you want to edit the user, the model needs:
the User data
a list of UserGroups
I'd use a model like this:
public class EditUserModel
{
public User User {get;set;}
public SelectList UserGroups {get;set;}
}
As you can see, I directly add the User as a property. But I don't add the list of categories as a property, because I don't need the whole list of categories, with all their properties in the view. Besides, if you unit test the controller you can verify that the SelectList is as expected (that couldn't be done if you created the User Groups list in the view)
But, what if you don't need all the properties of the user in the View? Is it worth removing the User property, and add individual properties for Name, Email, JoinedData, Active... ? I think the anser is NO. Imagine you add/remove or rename some of the User entity properties. If you had individual properties in the view model, you'd have to change them as well, before updating the View. And, if you rely on automatic mapping (auto mapper, value injecter) you would't even realized if you make some mistake.
I also said that the view model can be used for posting back data to the controller. So you could do this:
[HttpPost]
public ActionResult Edit(EditUserModel userModel)
If you do so, the model binder will populate the userModel with the values in the form controls. So you'lll get back a half empty model. In this case, the UserGroups list would be null, and, depending on how many of the User's properties you edit, the User could also have many null/non-initialized properties.
To avoid making errors, in some occasions is advisable to create a different model (and probably auxiliary classes) to make it clear what is expected to be posted to the model.
For example, if you have an action to show the whole user data, but which only allows to change its password, you could create a class with two properties: Password, and PasswordConfirmation.
In this case, the view model for the POST could only have the Password and PasswordConfirmation. And derive a model for the GET which has this inherited properties, and also the list of User Groups and the User.
Why inheriting and not using independent classes? Simply beacuse when you use something like Html.TextBoxFor(m => m.User.Name), the Model Binder will be able to set the Name property of the User property, only if the parameter for the post action has the same structure. I.e. if the view model for the get has this structure:
public ChangePasswordModel
{
public string Password {get;set;}
public string PasswordConfirmation {get;set;}
// extra properties, like the list of user groups, the user data...
}
And the model for the post has this structure:
public PostedChanegPasswordModel
{
public User User {get;set;}
}
The content of the input rendered by Html.TextBoxFor(m => m.EditedUser.Name) won't be bound to the User.Name of the PostedEditViewModel.
But if you make this:
public EditUserModel : PostedEditUserModel
{
// extra properties, like the list of user groups
}
the data will be bound without any problem.
In general you have to be careful with the models you use for posting and getting. And I recommend using as many different view models as neccesary.
When to use automatic property mapping to completely new view and different models?
You must have a very strong reason to have different view models. This could be a result of starting the application from outside in (i.e. design first) or because a team is developing the UI before or while the business logie is being implemented.
In this case you can find that the classes for the view models, and the views themselves are already defined, and are quite similart to your entities, but not exactly equal. This is one case when I think it can be good to use mappers.
The other reason to use different classes would be to decouple the interface from the logic. But this usually only happens in the previous case.
Regards viewmodels I treat them like a summary of the data you wish to work with.
So taking from your example, your viewmodel would contain data from both the User and UserSettings classes. Let's say you had a view named UserData.cshtml then I would code it up like so:
public class UserDataViewModel
{
public string Username { get; set; }
public bool AllowDirectEmails { get; set; }
// etc ...
}
public ActionResult UserData()
{
var viewModel = new UserDataViewModel();
viewModel.UserName = "Whatever";
viewModel.AllowDirectEmails = false;
// Or however you get the data for the user.....
return View(viewModel)
}
Hopefully you get the idea. So you are on the right track with merging information from externals classes into one viewmodel class. Bascially tie everything together in the viewmodel class.
I name the viewmodel class the same as the view that it's going to be used for. This can help documentation, as well as make it easier for devs new to the code to follow.
I'm hoping you guys can answer me a question?
I've only just started out using ASP.NET MVC3 have come unstuck at a certain point. I've been learning this stuff from books and I'm slightly unsure on a few things.
Can a VIEW, only have one #Model reference?
At the moment I have a VIEW setup with a HTTP-POST on a ViewResult, that validates the data in the View, entered by the user and then "on post", passes this info to a method that writes it back to a database(ADO.NET - Access). Now I need to change my VIEW, so that I can replace a couple of my text boxes for Dropdownlistfor controls. The Data to populate these controls will need to be passed in from the Database.
Would I be correct in saying that this data needs to be passed in the HTTP-GET Viewresult of the page, and if so, can i reference more than one #Model in this same View (*.cshtml).
I have a class that takes in the user response, and this is referenced in the View. But will i need to create a new class for the dropdownlist data and reference that too. So that in the background I populate the data into a SelectListItem, pass it to the View and then populate each drop down control within the view?
I'm sorry if this is poorly written, very hard to explain, I find learning from books hard and I'm pretty stuck now. Any help would be appreciated. Just to give me an understanding of how this all wraps around. I'm comfortable with the C# syntax, but very unsure of MVC3!
There are two ways you can handle this.
Use a View Model.
In this scenario you have a class that contains your data model as well as other things required by the view, so something like this:
public class ViewModel
{
public MyDomainModel Model { get; set; }
public IEnumerable<SelectListItem> SelectListItems { get; set; }
}
Use ViewBag.
In this case you add everything extra into the ViewBag dictionary. So in the controller, you'd have stuff like this:
ViewBag.SelectListItems = new SelectListItem[] { ... };
Then you can reference in the view itself
#Html.DropDownList("myselectlist", ViewBag.SelectListItems)
I think that this will help you pluralsight mvc3 intro. It sure helped me
I'm debating with myself about the best practice approach to controlling an Aggreate View Model class that I've created for my app... Let's say I have an aggregate model that has a PurchaseOrder object and a list of line items that belong to that Purchase Order, and a few other auxuliary/related objects. This view model is just a wrapper around all these objects that you would typcially need when working on any give PurchaseOrder.
After after creating an instance of this view model, I then want it to load up a PurchaseOrder (and it will load the PurchaseOrderLineItems automatically and saturate all the other related objects)...
So, to instruct the view model to load up a PurchaseOrder, is it more acceptable to:
Instruct the view model by setting a property on it (and let the property setter of the view model class respond by loading up the data)
ViewModel.PoNo = 1234;
or
Call a method on the view model to do the work:
ViewModel.LoadPurchaseOrder(1234);
Just to give a few mode detials about the Aggregate View Model, it basically looks like this:
public class ViewModel
{
//-- private fields
PurchaseOrder _Po = new PurcaseOrder();
List<PurchaseOrderItem> _PoLineItems;
Vendor _Vend = new Vendor();
int _PoNo;
//-- public properties here
ViewModel(){} // Constructor
}
Does this ViewModel serve any purpose other than relating all the PurchaseOrder informaton together? If not i would say you should pass your purchase order in the constructor of ViewModel because it seems like ViewModel would only be in a valid state if it had a PurchaseOrder.
EDIT: Given the 2 options you have listed, I think a method call makes more sense than setting a property as it is easier to tell that you are loading a PurchaseOrder into this ViewModel. As a developer, I wouldn't think that setting an integer property would end up loading all kinds of objects on the ViewModel, but one might expect that from calling a method.