CodeDigest.Com Logo
Featured:

Using Templated Helpers with EditorTemplates and DisplayTemplates in Asp.Net MVC

Tagged as: Asp.Net MVC Posted By

Templated Helpers helps to build UI HTML elements automatically based on the Model passed to it. The templated helpers such as @Html.EditorFor(), @Html.DisplayFor(), @Html.EditorForModel() emits HTML elements based on the datatype and meta data passed into is through DataAnnotations attributes. For example, @Html.EditorFor(model => model.LastName) will output a textbox element of type <input id="FirstName" name="FirstName" type="text"> based on the datatype string. We can customize this behavior using data annotations attributes to output a different element for the mode property if required.

These templated helper methods allows us to define editor templates and display templates using partial views for making the customization of UI elements centrally. For instance, we can define a Boolean template (Boolean.cshtml) under Shared/DisplayTemplates and Shared/EditorTemplates which will be automatically used by the @Html.EditorFor() and @Html.DisplayFor() for displaying Boolean values.

For understanding templated helpers, let’s build an Asp.NET MVC 5.0 application with Entity Framework. We will use a simple Employee-Department model and build a Employee Details and Employee Edit screen using templated helper methods.

Assuming you have an EmployeeController with edit() and details() action, we can generate a view using “Add View” dialogue by right clicking the edit Action method and selecting “Add View..”. In Add View dialogue, by selecting Templates as edit and Model class as Employee as seen below we can make the Scaffolding framework to generate the edit view using templated helpers.

For details view, repeat the steps we did for adding edit view and select Template as Details in the above “Add View” dialogue.

The generated views with templated helpers will look like below.

Edit.cshtml

<div class="form-horizontal">
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    @Html.HiddenFor(model => model.EmployeeId)

    <div class="form-group">
        @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
        </div>
    </div>
    
    @* Removed for brevity *@
</div>
 

Details.cshtml

<dl class="dl-horizontal">
    <dt>
        @Html.DisplayNameFor(model => model.FirstName)
    </dt>

    <dd>
        @Html.DisplayFor(model => model.FirstName)
    </dd>

    <dt>
        @Html.DisplayNameFor(model => model.LastName)
    </dt>

    <dd>
        @Html.DisplayFor(model => model.LastName)
    </dd>

@* Removed for brevity *@    
</dl>
 

When executed, the page will display the input controls and display controls automatically based on the model data type.

If you see the edit view (left pane in above image), the templated helper method used checkbox for “IsPermanent” property of Employee model. Please note, I have used data annotation’s Display attribute to change title of this field to “Are you a permanent employee”.

Let’s now use EditorTemplates and DisplayTemplates to customize this property to make the templated helper use RadioButton control with Yes or No option.

Customization Using EditorTemplates and DisplayTemplates

By convention, the templated helper methods will look into Shared/EditorTemplates and Shared/DisplayTemplates for finding the partial view for rendering the UI elements. So, let’s now create these 2 folders under Views/Shared folder and include Boolean templates for displaying radiobutton instead of CheckBox.

EditorTemplates\Boolean.cshtml

@model bool
<div class="radio">
    <label>
        <input type="radio" name="@ViewData.ModelMetadata.PropertyName" id="@ViewData.ModelMetadata.PropertyName" value="true" @( Model ? "checked":"")>
        Yes
    </label>
</div>
<div class="radio">
    <label>
        <input type="radio" name="@ViewData.ModelMetadata.PropertyName" id="@ViewData.ModelMetadata.PropertyName" value="false" @( !Model ? "checked":"")>
        No
    </label>
</div>
 

DisplayTemplates\Boolean.cshtml

@model bool

<label>@(Model ? "Yes":"No")</label>

 

In the above partial views, I have used plain HTML elements you can even use html helpers like @Html.Radiobutton() to display HTML controls in these templates. So, the final structure in solution explorer will look like below.

Now, on execution you will see the templated helpers will use the templates defined in EditorTemplates and DisplayTemplates folder. Refer the below output. The left pane in the image below if how edit screen will look like and right is the details screen.

In the above example, the partial view template Boolean.cshtml is automatically used by the @Html.EditorFor() and @Html.DisplayFor() since the name of the partial view matched with data type of the property Employee.IsPermanent. Similarly, we can define partial view templates for other data types like Int32,Decimal, etc. in editor and display template folders. Another very good use of this templates is for DateTime type where we can include a date picker in a editor template which can be used accross the application wherever datetime input field is needed. So, whenever we need to make any changes to datepicker then we can do it at one place to get that reflected everywhere.

We can also define partial view templates for specific purpose like Gender.cshtml and instruct the templated helper methods to use it by configuring the UIHint data annotation attribute in the Employee model object. In our edit and details page seen above, we are using Textbox control for Employee.Gender property. Let’s change this to add a DropDownList with Male and Female as option by defining a partial view template called Gender.cshtml in editor and display template. Partial view code below.

EditorTemplates\Gender.cshtml

@model string
<select class="form-control" name="@ViewData.ModelMetadata.PropertyName" id="@ViewData.ModelMetadata.PropertyName">
    <option @(Model == "Male" ? "selected":"")>Male</option>
    <option @(Model == "Female" ? "selected":"")>Female</option>
</select>

 

DisplayTemplates\Gender.cshtml

@model string

<label>@Model</label>

 

Since the name of the partial view templates are not matching the datatypes, let’s use UIHint attribute to let the helper methods to use these templates. The employee model with UIHint defined for Gender property is below.

 

[MaxLength(10)]

[Required]

[Display(Name = "Gender")]

[UIHint("Gender")]

public string Gender { get; set; }

 

When executed, we can see the Gender will display dropdownlist and the label for edit and details view respectively as seen in below image.

Another good use of this type of templates is to add Rich Text Editor for fields that requires textarea where we could include  RichText editors like CKeditor or tinyMCE editor in editor templates.

Defining Templates for Complex Types

We can also define editor and display templates for complex object or user defined objects and make the templated helpers to render UI elements based on that. For example, we can define a editor template and display template called Department.cshtml and it will be used when for rendering UI elements for Department object when using the templated helper method @Html.EditorForModel() method. To demonstrate, let’s define Department.cshtml in both EditorTemplates and DisplayTemplates folder as seen below.

EditorTemplates\Department.cshtml

@model EmployeeMaintenance.Models.Department
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.DepartmentId)

        <div class="form-group">
            @Html.LabelFor(model => model.DepartmentName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.DepartmentName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.DepartmentName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}
 

DisplayTemplates\Department.cshtml

@model EmployeeMaintenance.Models.Department
<div>
    <h4>Department Details</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.DepartmentName)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.DepartmentName)
        </dd>
    </dl>
</div>
 

To use these templates, we have to use the @Html.EditorForModel() method from both edit.cshtml and Details.cshtml views of DepartmentController as seen in below code.

edit.cshtml

@model EmployeeMaintenance.Models.Department

@{
    ViewBag.Title = "edit";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Edit a Department</h2>

@Html.EditorForModel()

<div>
    @Html.ActionLink("Back to List", "Index")
</div>
 

Details.cshtml

@model EmployeeMaintenance.Models.Department

@{
    ViewBag.Title = "Details";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

@Html.DisplayForModel()

<p>
    @Html.ActionLink("Edit", "Edit", new { id = Model.DepartmentId }) |
    @Html.ActionLink("Back to List", "Index")
</p>
 

Thus, we have seen how to use EditorTemplates and DisplayTemplates for defining reusable partial view templates which can be used to control the view elements from a centralized location in Asp.Net MVC applications. Download the source and see it in action!

 

 



Feedback

Comments

Custom Attributes
So using ViewData or some other object related to the editor template, how do we include custom attributes like class or data-plugin or data-something-else?
Commented by Keith C. on 8/2/2018 2:29:29 PM