Partial views in ASP.NET MVC are great. They allow you to update only a part of the DOM without having to perform a full page refresh or a postback. Surely, there are many ways to achieve this, such as ajax and WebAPI, however, partial views have one major benefit over the other methods:
Strongly-typed datamodels!
Using this approach, the controller can push a nice object model back to the partial view instead of Json and we can take advantage of Razor and/or scaffolding for data presentation while enhancing the whole user experience.
In this example, we will create a master page that contains a drop-down box and then we will add a partial view to display data filtered by the drop-down value.
1. The parent/master view
The partial view needs to live inside a master/parent page, so let's create one:
@model Models.FullAndPartialViewModel
@{
ViewBag.Title = "My Master Page";
}
<script type="text/javascript" src="CDN or local jquery file"></script>
<div id="container">
<label for="ddlCategory"><strong>Select a category</strong></label>
@Html.DropDownListFor(m =>m.CategoryId,
new SelectList(Model.CategoryList, "CategoryId", "CategoryName", Model.CategoryId), new { id = "ddlCategory", @class = "test" })
<br/><br/>
<div id="dvCategoryResults">
@{Html.RenderPartial("CategoryResults", Model);}
</div>
</div>
Nothing fancy here. There are some HTML elements missing (head, body etc), but I assume that these are already defined. There are, however, two things that you need to note:
- you need a reference to the jquery. This can be either local or through a CDN
<script type="text/javascript" src="CDN or local jquery file"></script>
- and, you need to put your partial view inside a div as we will reference the div later in the ajax call.
2. The partial view###
The partial view is just a very slimmed down version of a normal view. You only add the html elements that are required. Usually, you should avoid putting any javascript and css references in the partial view and try to make it as lightweight as possible. The name of the view should be the same as the one used in the @Html.RenderPartial()
declaration on the master view, i.e. CategoryResults
@model Models.FullAndPartialViewModel
<table>
<thead>
<tr>
<th>Category</th>
<th>Product</th>
<th>Price</th>
</tr>
</thead>
<tbody>
@foreach (var product in Model.Products)
{
<tr>
<td>@product.Category</td>
<td>@product.Product</td>
<td>@product.Product</td>
</tr>
}
</tbody>
</table>
3. The controller
The controller consists of 3 methods:
- one for loading the whole page(parent and partial) -
Index()
- one for reloading/refreshing the partial view -
GetCategoryProducts()
- and a helper method to create and populate the datamodel -
GetFullAndPartialViewModel()
[HttpGet]
public async Task<ActionResult> Index()
{
var model = await this.GetFullAndPartialViewModel();
return this.View(model);
}
[HttpGet]
public async Task<ActionResult> GetCategoryProducts(string categoryId)
{
var lookupId = int.Parse(categoryId);
var model = await this.GetFullAndPartialViewModel(lookupId);
return PartialView("CategoryResults", model);
}
private async Task<FullAndPartialViewModel> GetFullAndPartialViewModel(int categoryId = 0)
{
... code omitted...
// populate the viewModel and return it
return fullAndPartialViewModel;
}
4. The DataModel
public class FullAndPartialViewModel
{
public int CategoryId { get; set; }
public List<CategoryProductItem> Products { get; set; }
public List<CategoryListItem> CategoryList { get; set; }
}
5. The Ajax code
The idea here is to reload the partial view on the page when the user selects a different category from the drop down list. At the bottom of you master page, below the html, add the following javascript code:
<script type="text/javascript">
$(document).ready(function () {
$("#ddlCategory").change(function () {
var categoryId = $("#ddlCategory").val();
$("#dvCategoryResults").load('@(Url.Action("GetCategoryProducts","Home",null, Request.Url.Scheme))?categoryId=' + categoryId);
});
});
</script>
NOTE: The javascript code can and should live in an external .js file, but, for the sake of simplicity, I placed it inline.
EDIT As a reader pointed out (thanks Marc), if you place your code in an external .js file, ensure that you remove any Razor code as it will break things. In the example above, @UrlAction.. should be replaced with a proper link.
What this little piece of code does is pull the value of the categoryId from the drop down, execute a call to the GetCategoryProducts()
method in the Home
controller and then update the content of the div containing the partial view with the new data.
With the use of partial views, it is very easy to extend your views and make them more responsive and user friendly. What is even greater is that jQuery makes it a piece of cake to interact and update partial views with only a few lines of code!
Happy coding...