3.11 MVC ViewModels
We’ve talked about Views, and we’ve talked about Models, and now it is time to discuss ViewModels. A ViewModel is a Model specifically designed to work with a View, and in this lesson, you will learn how to use a ViewModel when a plain old Model isn’t enough to get the job done.
1.Introduction1 lesson, 02:19
2.MVC Basics4 lessons, 15:13
3.Designing Within MVC14 lessons, 1:58:58
4.Conclusion1 lesson, 01:11
3.11 MVC ViewModels
Hello and welcome back to ASP.NET MVC for designers. What happens when a model isn't enough to get the job done? For example, on our shopping page we tied this page to the product model. And the product model gave us everything that we needed to display the information that we see here on this page. It gave us product names, product prices and product descriptions. However, what if we wanted to add a little bit of customer information to the page? What if we wanted to display some kind of welcome message and include the customer's name in it? In that case, we would need more than just the product model to display all the data that we need. We would also need a customer model, then we would have two separate models that we would want to bring in to the page and we can't really do that. So what we're going to do, is we're going to create a view model, which is basically a model specifically designed to display everything on the page that we need. All of the data that we're going to need for a given page. So a view model can include information from other models. So we can include information from the product model as well from the customer model. So let's start by creating another copy of our project, and we'll call this new copy, Store09 and then we'll open up that copy in Visual Studio. So we'll close the old version here and we have a folder for our models and inside that folder we have a product model. I'm gonna make a quick copy of that. I'm just gonna hit Ctrl+C and then Ctrl+V to copy and then paste it and then I'm gonna rename this copy Customer. So we need to change some of the text here, we're going to change the class name here to customer and then we'll edit a few of these fields. So instead of ProductName, we might have FirstName. You can call it Customer FirstName if you want to, and then I'm also going to include LastName and then we might have some other bits of information as well, such as address, city, which also needs to be a string, so we will change that from an int to a string. And then we will just make a couple copies of that and we have city. We'll add state and we'll add zip and maybe even one more for phone number. So now we have a customer model in addition to our product model. And let's say that in addition to using our product model on our index page for the shopping controller, we also wanted to include a little bit of customer information. Well how would we do that? Well we're gonna do that using a view model. Now you can create your view model in the same folder as your other models, but I prefer to keep them in a separate folder. So I'm gonna right click on my Store project and I'm gonna go to Add, and I'm gonna add a new folder and I'm gonna call this folder View Models. Then I'm gonna right-click on the View Models folder, and we're gonna add a new class here. So we'll add and then I'm looking for New Item and then we'll go up to the code option near the top just under visual C#. And we'll select Class, and I'm gonna call this class Shopping Index View Model and we'll click on Add. So now we've got our Shopping Index ViewModel and we're gonna treat this the same way as we would any other model where we're simply going to add a couple of properties to it. And when I'm adding properties, all I'm asking myself is, what do I want to display on the ShoppingIndexView. Well, I want to display the information for a customer and the information for a product. So, all we need to do is to create a couple of properties to capture that information. So, again, we're gonna use the public keyword and this particular item is going to be of type customer. Now, you'll notice customer doesn't show up here. So let's create a using statement first, or we could type out customer and then generate the using statement, as we've done before. But we're gonna go to using Store, which is the name of our project dot models. And that will give us access to both customer and products because both of those are in the Models folder. So we're using Store.Models let me zoom in on the code a little bit and you can see we have a semicolon at the end of that statement and then we can go back to our property here. So we're going to create a property here that represents a customer. So public and now you'll notice that my code hinting gives us the option for Customer, so we can double-click on that and then we need to give it a name. And I'm just gonna give it the same name, Customer with a capital C. Now you can certainly give it a different name if you want to, but one popular convention the way a lot of developers do it is they simply call it the same name and that's usually what I see. So again we have public which simply tells us that we can access this anywhere. And then we have the type for this particular property and the type of this property is an instance of the customer class. So we're using Customer here and then the name that we're giving to this particular property which is Customer. And then remember that we need to put our getter and setter here, so get and set. Now we're gonna do the same thing for our products, except remember we need a list of products for our index page, not just a single product. So instead of just typing public Product, we actually need a list of products. So we're gonna undo that, and we're gonna do List with a capital L and then inside angle brackets, we'll point to the product class that we created, which is Product with a capital P. So we're creating a list of products, and the common naming convention for that is just to put whatever model name we have here as a plural since it's multiple products. So then again we will add our get and set and we're good to go. So we have two things that we need for this particular view for our shopping index page where we are showing our list of products. We need a Customer, so that we can display the current logged in customers first and last name and then a List of Products. And it's as easy as that. Now, all we need to do now is save that file and go into our views. We're gonna go into the shopping folder and we will go into the index view within that shopping folder. So on the index view you will notice that we currently have our model set to a List of Products. Well we're not doing that anymore. Now we're creating a model or we're using a model that is actually going to be an instance of the ShoppingIndexViewModel. So instead of store.models.product in fact we've gotta get rid of the list altogether. So I'll highlight everything after model. So we simply have model space and then I'm gonna point to Store.ViewModels, because that's the folder that our view model is in, dot, and then we have our ShoppingIndexViewModel. Now keep in mind that this still is not going to work because our model is now a different type. It's no longer a list of products, instead it's an instance of this View model that we just created. So when we point to Model here, we're no longer pointing to a list of products, so we can't do a for each loop on this model object anymore. We have to change that around a little bit, but before we can change it around we need to jump back into our controller. So I'm gonna go back to the shopping controller and in the index view, remember we created our model here and we set it up as a list of products. We're no longer gonna do that, instead, this is gonna be an instance of ShoppingIndexViewModel. Now, we're not gonna see that in our code hinting yet, because we didn't add that to a using statement. But let's zoom in here so we can see that a little better. I'm just gonna type out, shopping index view model and then, we'll click on that, and we'll get this little, blue rectangle below it. And then, we'll grab this drop-down, and we'll add this using statement, Store.ViewModels and, now we're good. So, Instead of a new list of products here, we're gonna create a new instance of ShoppingIndexViewModel. And we still need open and close parentheses there, semicolon to end our statement. Now inside this ShoppingIndexViewModel, remember we have our list of products here and we gave it a name of Products. So we can now access that products list by pointing to ShoppingIndexViewModel, from within our controller. So, let's go back to our controller and instead of model.Add, remember this model is no longer a list of products. Instead, our list of products is inside that model, so we're gonna type model.Products.add, in that way we will add this product to the list of products that's now stored inside our shopping index view model. So we're gonna do the same thing for our other add statements. We'll do model.products.add, we'll do it down here as well and finally for our fourth item. So we're doing the exact same thing. We're adding four different products to a list of products, but now that list of products is stored inside our model instead of being represented by the model itself. Also, if we want to be able to access our customer's first and last name on the view, we also need to assign those values here. So after all of our modelProducts.Add statements. But before we return the view, I'm going to also point to model.Customer and then we can type in dot and get a list of properties we added there, and all we really want to access here is first and last name. So we're going to grab first name here and set it equal to Craig. And then we'll grab model.Customer.LastName and set it equal to Campbell, and now we have access to these two properties as well from within our view. So we're still passing Model into the view but that model is a different type now. Remember, it's now an instance of shopping index view model instead of just being a list of products. So, with that saved, let's jump back into our index file one last time and let's update our for each statement. Now I want you to think about it for a second before I do this for you. I want you to think about it, pause the video for a second if you need to, but think about how you would change this for each statement so that it still works. So I'll give you a second to pause the video and figure that out and if you can't figure it out, don't worry about it. You can just unpause the video and I will show you. So what we're gonna do is, we're still gonna use the same for each loop, but remember this model, as I've mentioned several times before, but I really want you to understand this, this model is no longer a list of products. Instead this model is an instance of the ShoppingIndexView model that we created which contains a list of products inside it. And that list of products, if we go back to our view model, is simply called Products. So we can access this list of products by typing ShoppingIndexViewModel.products. And remember, in our view, we can refer to our shopping index view model simply by saying, Model or model with a capital M when we type it out in Razor syntax. So we're still looking for each product inside that list of products, but now we refer to that list of products by typing model.products. And now you'll see our squiggly red underline goes away and everything works just like it did before. So now all I have left to do, is to add our first and last name here. So I'm just gonna add another paragraph after our H2 but before our second paragraph. And we're going to say welcome, space and then will point to first name and last name. So I'm going to take the at symbol, and then in order to access that first name remember we need to type Model, first of all, to access that shopping index field model.customer.firstname. Now if we want to string two things together here such as first name and last name, all I need to do is put a space here and then we'll do the same thing again, except this time we'll do Model.Customer.LastName. So let's test that and see if it works. I'm going to save our index.cshtml file. I'm going to hit Control+F5 to test in the browser. And if you work in ASP.net fr any length of time you're going to encounter a screen that looks something like this. Now what we're seeing here is a null reference exception. It says object reference not set to an instance of an object. What that means is, on this particular line that's highlighted red, we have an object that has a null value. Which object do you think it is that has a null value? We know model doesn't have a null value, and null basically just means that no value exists for it. But we know that a value exists for Model, because we set it equal to a new ShoppingIndexView model up here, so it must be Products. And sure enough if we go back to our code and jump into our ShoppingController. Remember before, when our model was a list of products, we set that model equal to a new list of products but we haven't done that here. We haven't created a new list of products. All we've done is we've said model.Products.Add. Well, at this point, model.Products doesn't really exist, or it doesn't have any value assigned to it. It exists in our view model, but until we assign it a value, until we actually create that list of products, it doesn't exist. So we're trying to access something that's null, or something that doesn't have a value. So what we need to do is after we assign our Model a value, we need to assign Products a value. So we're going to point to model.Products and set that equal to a new list of product. And remember when you create a new list of product, we also need to add open and close parentheses to the end, semi-colon to end our statement. Now we're gonna have this same issue when we come to our customer, because down here, we've set model.Customer.FirstName equal to Craig, but model.Customer does not exist yet. So down here, I'm gonna set model.Customer = new Customer. Open and close parentheses, semicolon to end our statement, and that should take care of all of our errors. So let's save that, and then we're going to hit Cntrl+F5 once again, because remember, we Edited a CS file, not just an HTML file. And when we edit a CS file, we need to recompile by hitting Ctrl+F5 again, we can't just refresh the browser. So once we rebuild that, we can see that everything compiles just fine. And now if we go to the Products page we see all of the data that we're looking for. We see the first and last name here. And we might make it look better by maybe putting it in bold font or something like that. But we see our customer data here and then down at the bottom we see all of our product data. So, that's how you can combine multiple models within a single view using a View model in MVC. Thank you for watching, and I'll see you in the next lesson.