In the last module we completed the category filter feature for the vehicle results on the main page of the application. In this module we are going to break out the code (HTML, Razor, and C#) for a single vehicle result, or one table row representing a single vehicle, into a template using a partial view.
A partial view in ASP.NET Core MVC is a reusable component with a fragment of code containing HTML, Razor, and C# that can represent a portion of a web page. It’s similar to a regular view, but is intended to be encapsulated in other views, rather than being rendered on its own.
Some key benefits of partial views are they help avoid code duplication and are reusable. But, I like using them to break out longer pieces of html and razor to make the main page the partial view will sit in more readable. That way you’re not forced to look at all of the logic in one file. You can get an idea of the flow of the Index file just by seeing a call to to a partial view, in this case to layout vehicle results in html table rows.
Create the Partial View
In the Views/Home
folder, create a Razor file named _VehicleTableRowResult.cshtml
FredsCars\Views\Home_VehicleTableRowResult.cshtml
@model Vehicle
<tr>
<td>
<img src="@Model.ImagePath"
class="result-image" />
</td>
<td>
@Html.DisplayFor(modelItem => Model.Status)
</td>
<td>
@Html.DisplayFor(modelItem => Model.Year)
</td>
<td>
@Html.DisplayFor(modelItem => Model.Make)
</td>
<td>
@Html.DisplayFor(modelItem => Model.Model)
</td>
<td class="d-none d-lg-table-cell">
@Html.DisplayFor(modelItem => Model.Color)
</td>
<td class="d-none d-md-table-cell">
@Html.DisplayFor(modelItem => Model.Price)
</td>
<td class="d-none d-md-table-cell">
@Html.DisplayFor(modelItem => Model.VehicleType.Name)
</td>
</tr>
In the razor code above, we have basically cut the code from the parent Home/Index
view that creates a vehicle table row result for each vehicle in the foreach loop and copied it to the new partial view.
We named the view starting with an underscore ‘_’ character. Starting a view name with an underscore character signifies that the razor file should not be loaded on it’s own. You don’t have to use this convention but I find it helpful to identify partial views more easily.
We placed the partial view in the Views/Home folder. In this location, only action methods in the Home controller will be able to find this partial view. I did this because embedding a result in a table row is not truly reusable because we are forced to place the result in a tbody or table html element.
If we truly wanted this component to be reusable we would place it in the Views/Shared folder. In this location any action method from any controller would be able to find this view. I would have been more likely to place the view in the Shared folder if we were using div elements to encapsulate a result and the Bootstrap grid system like we did in Chapter One. But in this chapter I wanted to show a common layout theme in web applications; a table and table rows to show results. This layout also makes it easier to show the sorting feature. In Chapter four, ASP.Net Core Razor Pages – PageModels and Views, we will return to our original layout with three Vehicle results per row in an HTML div element using the Bootstrap Grid system.
At the top of the Razor file the model is defined as type Vehicle.
@model Vehicle
We access each property of a Vehicle to lay out in results using the Model property of a Razor view file instead of ‘v’ in theforeach (var v in Model.Vehicles)
loop we were previously using in the parent view.
The following is an example using the Status property of a Vehicle.
<td>
@Html.DisplayFor(modelItem => Model.Status)
</td>
Call a Partial View from a Parent View
Now we need to make a call to the _VehicleTableRowResult partial view from the Home/Index parent view. Make the following modification to the Index.chtml file in the Views/Home folder.
FredsCars\Views\Home\Index.cshtml
@model VehiclesListViewModel
@{
ViewData["Title"] = "Welcome";
}
<div class="container-fluid my-4 text-center">
<h1>Welcome to Fred's Cars!</h1>
Where you'll always find the right car, truck, or jeep.<br />
Thank you for visiting our site!
<div class="container-fluid mx-0 row"
style="margin-top: 20px;">
<!-- Categories -->
... existing code ...
<!-- Results -->
<div class="col">
<h3 class="bg-dark text-success">ALL Results</h3>
<table class="results table table-striped">
<thead>
... existing code ...
</thead>
<tbody>
@foreach (var v in Model.Vehicles)
{
<partial name="_VehicleTableRowResult"
model="v" />
}
</tbody>
</table>
<div id="page-links"
page-model="@Model.PagingInfo"
page-action="Index"
paging-classes-enabled="true"
paging-btn-class="btn"
paging-btn-class-normal="btn-outline-dark"
paging-btn-class-selected="btn-primary"
sort-column="@Model.SortingInfo.CurrentSortColumn"
sort-order="@Model.SortingInfo.CurrentSortOrder"
class="btn-group mt-3">
</div>
</div>
</div>
</div>
In the parent Home/Index razor view above, instead of laying out seven html td elements for each Vehicle iteration in the forloop, we simply make a call to a template encapsulated in a partial view.
@foreach (var v in Model.Vehicles)
{
<partial name="_VehicleTableRowResult"
model="v" />
}
In the code snippet above, we make the call to the _VehicleTableRowResult
partial view using the partial tag helper. The tag helper’s name attribute is assigned the name of the partial view to call without the .cshtml extension. And we use the model attribute to pass the variable v representing the Vehicle object in each iteration of the forloop
.
If you restart the application and run it there should be no changes from before and the behavior as far as filtering, paging and sorting should remain the same.
What’s Next
In this module we broke out the Vehicle result table rows into a template using a partial view.
In the next module we will learn about View Components and make the category buttons section dynamic.