Display templates
MVC has a bunch of handy helpers that we can use to create our views more efficiently. One such helper are the display templates that are used within views.
@Html.DisplayFor(e => e.Username)
The DisplayFor(Func<TModel, TValue> expression)
function uses the type of the property in the expression to display the property value.
<!-- DisplayFor on string UserName = "daniel.imms" --> <span class="field-validation-valid" data-valmsg-for="UserName" data-valmsg-replace="true">daniel.imms</span>
Defining custom templates
We can override the default templates by placing our custom display templates into the path Views/Shared/DisplayTemplates/<type>.cshtml
. They are structured like any MVC partial view. An example usage could be adding a dollar sign to the front of a decimal's value.
Model
public class TestModel { public decimal Money { get; set; } }
Views/Shared/DisplayTemplates/decimal.cshtml
@model decimal @{ IFormatProvider formatProvider = new System.Globalization.CultureInfo("en-US"); <span class="currency">@Model.ToString("C", formatProvider)</span> }
View
@model TestModel @Html.DisplayFor(e => e.Money)
Output
<span class="currency">$3.50</span>
UIHint
attribute
To use a custom display template that isn't based on the name of the type, we can set a UIHint
attribute on the property. So we could make a 'Currency' display template instead of assuming that all decimals are dollar amounts. To do this we would simply rename our decimal.cshtml
file above to Currency.cshtml
and apply the UIHint
attribute to the model property like so:
public class TestModel { [UIHint("Currency")] public decimal Money { get; set; } }
Editor templates
Editor templates can be overridden in the same way using the EditorFor
function and placing the custom templates in Views/Shared/EditorTemplates/<type>.cshtml
.
Passing additional data
It may be necessary to provide more than just a property to the custom template. For example if we want to display a list of radio buttons with one of them selected. This could be achieved by passing in the list of options as 'view data' and having the property as an int?
which would represents the index of the selected option. MVC provides an overload that allows us to pass in this additional view data to the custom template, EditorFor(Func<TModel, TValue> expression, Object additionalViewData)
.
Model
public class UserModel { [UIHint("RadioButtonList")] public int? UserRole { get; set; } }
Controller
public class TestController : Controller { public ActionResult Test() { return View(new UserModel() { UserRole = 2 }); } }
View
@model UserModel @{ // In a real system we would get this list from the database List<SelectListItem> list = new List<SelectListItem>(); list.Add(new SelectListItem() { Text = "Admin", Value = "0" }); list.Add(new SelectListItem() { Text = "Project manager", Value = "1" }); list.Add(new SelectListItem() { Text = "User", Value = "2" }); } @Html.EditorFor(e => e.UserRole, new { List = list })
Views/Shared/EditorTemplates/RadioButtonList.cshtml
@model int? @using System.Collections @using System.Web.Mvc; @{ var list = (List<SelectListItem>)ViewData["List"]; } <ul class="radio-list"> @foreach (var item in list) { <li> @{ var radioId = ViewData.TemplateInfo.GetFullHtmlFieldId(item.Value); var checkedClass = (item.Value == Model.ToString() ? "checked" : string.Empty); <input type="radio" id="@radioId" name="@ViewData.TemplateInfo.HtmlFieldPrefix" value="@item.Value" checked="@checkedClass" /> <label for="@radioId">@item.Text</label> } </li> } </ul>
Output
<ul class="radio-list"> <li> <input type="radio" id="UserRole_0" name="UserRole" value="0" checked="" /> <label for="UserRole_0">Admin</label> </li> <li> <input type="radio" id="UserRole_1" name="UserRole" value="1" checked="" /> <label for="UserRole_1">Project manager</label> </li> <li> <input type="radio" id="UserRole_2" name="UserRole" value="2" checked="checked" /> <label for="UserRole_2">User</label> </li> </ul>
Usage examples
- Format currency
- Format dates in a particular way
- Format credit card numbers
- Display a list of radio buttons or check boxes
- Add custom classes/IDs/structure to the output markup