Templates
- 8 minutes to read
Note
This topic explores component customization. For more information on the DevExpress ASP.NET Core Application Template for Microsoft Visual Studio, refer to the following topic: Bootstrap a New DevExtreme Project with Templates and Layouts.
Templates allow you to customize individual parts of a DevExtreme component. Different DevExtreme components offer different Template methods. View the API page of an individual component for a full list of templates that you can set.
For example, you can customize the following parts of a DataGrid component:
Other popular templates include:
You can use templates to nest DevExtreme components. The image below depicts a DataGrid
nested inside a Popup
:
Table of Contents
Basic Capabilities
Define a Simple Template
Simple templates can include plain HTML, Razor code, and JavaScript.
To define a short template without Razor code, pass a String
with HTML to the template definition method.
@(Html.DevExtreme().List()
.ItemTemplate("<div></div>")
)
Use ERB-style constructs to include template parameters or embed JavaScript code:
@(Html.DevExtreme().List()
.ItemTemplate("<div><%- obj.Parameter %></div>")
)
To define a multi-line template, pass a @<text> block to the template method:
@(Html.DevExtreme().List()
.DataSource(DataSource)
.ItemTemplate(@<text>
<div><%- Name %></div>
</text>)
)
Define a Function-based Template
Use the new JS()
expression to define a template as a JavaScript function. This technique can be useful in the following cases:
- You need to render the same template in several different ways, depending on conditional logic.
- You need to modify the template container.
- You need to perform logical operations with template parameters.
The myList_itemTemplate
function in the example below uses jQuery to apply a custom CSS class to template items. The function can access the itemIndex
and itemElement
template parameters.
function myList_itemTemplate(itemData, itemIndex, itemElement) {
itemElement
.addClass("my-custom-style")
.append(
$("<span>").text("Item index: " + itemIndex + ", Name: " + itemData.Name)
);
}
Store Templates Externally
You can store template definitions outside of the component declaration. This can be useful in the following cases:
- You want to use the same template in multiple components.
- You want to use large templates.
- You need to nest templates.
Store templates in Razor partials
You can store a template in a Razor partial:
@(Html.DevExtreme().Popup()
.ID("myPopup")
.ContentTemplate(@<text>
@(await Html.PartialAsync("_MyPopupContentTemplate"))
</text>)
)
Use Named Templates
Named Templates are easier to access, but you cannot nest them.
Template names should be unique. You can declare a Named Template in the same Razor file as the component that uses the template. Alternatively, you can store your templates in the layout file.
- Use the
using(Html.DevExtreme().NamedTemplate(...))
method to create a template definition. - Use the
*Template(TemplateName name)
method to apply the template.
@(Html.DevExtreme().Popup()
.ID("myPopup")
.ContentTemplate(new TemplateName("myPopupContentTemplate"))
)
@using (Html.DevExtreme().NamedTemplate("myPopupContentTemplate")) {
@(Html.DevExtreme().List()
.DataSource(ListDataSource)
.ItemTemplate(@<text>
<div><%- Name %></div>
</text>)
)
}
Embed JavaScript Code, Special Characters, and Raw HTML into Your Template
DevExtreme uses ERB-style delimiters (<%
and%>
) to indicate template elements that require special evaluation.
Embed JavaScript code
Enclose each line of JavaScript code in ERB-style delimiters (<%
and%>
). DevExtreme executes this code on the client when it renders the template.
@(Html.DevExtreme().Calendar()
.CellTemplate(@<text>
<% if(view !== "month") { %>
<b><%- text %></b>
<% } else { %>
<%- text %>
<% } %>
</text>)
)
Encode special characters and access template parameters
Use the <%- %>
delimiters to encode special characters as HTML entities and access template data.
The <%- <b>John</b> %>
expression returns the <b>John</b>
string.
The <%- obj.prop1 %>
expression returns the prop1
template parameter.
Embed raw HTML
Warning
Raw HTML evaluation can make your application vulnerable to cross-site scripting (XSS).
Use the <%= %>
delimiters to evaluate raw HTML.
Advanced Capabilities
Access Template Data
Each template offers access to objects with template-related data, otherwise known as template parameters. The names of these objects end with the word Data or Info. The client-side API reference details available parameters for each template. For example:
- The DataGrid cell template can access the
cellInfo
object with properties such asvalue
,text
, andcolumnIndex
. - The List item template can access the
itemData
object with item or dataSource data.
You can use <%- %>
delimiters to reference template data inside the template.
<%- obj %> // Returns the parameter in its entirety.
<%- obj.prop1 %> // Returns a single property of the parameter.
<%- prop1 %> // Parameter properties are available as standalone variables within the scope of the template.
For example, if you define the following Data Source:
object[] DataSource = new[] {
new { Name = "John" },
new { Name = "Jane" }
};
You can access the Name
parameter as follows:
@(Html.DevExtreme().List()
.DataSource(DataSource)
.ItemTemplate(@<text>
<%- Name %> <!-- As a free variable -->
<%- obj.Name %> <!-- As a property -->
</text>)
)
You can use JavaScript code to process template data.
Use Templates to Nest DevExtreme Components
You can use templates to place DevExtreme components inside other DevExtreme components.
Note
- You cannot nest multiple templates in a single template definition. Use external templates instead.
- Set unique IDs for components that you place inside templates.
The following example from the Drill Down PivotGrid demo embeds a DataGrid into a Popup:
@(Html.DevExtreme().Popup()
// ...
// Specifies the contents of the Popup control
.ContentTemplate(@<text>
@(Html.DevExtreme().DataGrid<Sale>()
.Columns(columns => {
columns.AddFor(m => m.Region);
columns.AddFor(m => m.City);
columns.AddFor(m => m.Amount);
columns.AddFor(m => m.Date);
})
)
</text>)
)
The result appears as follows:
Use Template Parameters to Pass Component Configuration Data
You can use template parameters to pass configuration data to a nested control.
The cell template in the example below includes a button
that receives its value from a template parameter.
- The new JS expression evaluates the content of the
value
parameter. - A short anonymous function passes the
value
parameter to thehandleGridButtonClick(cellValue)
event handler.
@(Html.DevExtreme().DataGrid()
// ...
.Columns(columns => {
columns.Add()
.DataField("Name")
.CellTemplate(@<text>
@(Html.DevExtreme().Button()
.Text(new JS("value"))
.OnClick("function() { handleGridButtonClick(value); }")
)
</text>);
})
)
<script>
function handleGridButtonClick(cellValue) {
alert("Cell value:" + cellValue);
}
</script>
Note
You can pass a short inline handler function directly to the handler method:
.OnClick("function() { alert(value); }")
Refer to the Events and Callbacks guide for more information.
Master-Detail Grids commonly require component nesting. In the following example, the detail section of a DataGrid includes a different DataGrid. The LoadParams
option of the detail grid’s DataSource
receives its value from the data.OrderID
parameter.
View Full Demo: Master-Detail View
@(Html.DevExtreme().DataGrid()
.DataSource(d => d.WebApi().Controller("DataGridMasterDetailView").Key("ID"))
.Columns(columns => {
columns.Add().DataField("FirstName");
columns.Add().DataField("LastName");
// ...
})
// Configures the Master-Detail UI
.MasterDetail(md => md
.Enabled(true)
// Specifies the contents of the detail section
.Template(@<text>
@(Html.DevExtreme().DataGrid()
.DataSource(d => d.WebApi()
.Controller("DataGridMasterDetailView")
.LoadAction("TasksDetails")
// Use "data.ID" in LoadParams
.LoadParams(new { id = new JS("data.ID") })
)
)
</text>)
)
)
Multi-Level Nesting
You can create multiple levels of nested DevExtreme components. To make template data from higher-level components accessible further down the DOM tree, propagate this data through intermediary components.
As an example, the TabPanel
in the Advanced Master-Detail View demo contains a DataGrid
. This grid uses another template to render its detail section.
To pass data from the TabPanel
to the grid’s detail section, we need to first pass it to the grid as a custom option (tabExtras
):
@(Html.DevExtreme().DataGrid()
.KeyExpr("ID")
.DataSource(MasterGridDataSource, key: "ID")
.MasterDetail(m => m
.Enabled(true)
.Template(@<text>
@(Html.DevExtreme().TabPanel()
.Items(items => {
items.Add()
.Title("Tab 1")
.Option("tabExtras", new {
masterKey = new JS("key")
})
.Template(new TemplateName("tab1Template"));
})
)
</text>)
)
)
@using (Html.DevExtreme().NamedTemplate("tab1Template")) {
<!-- Use tabExtras.masterKey to configure a detail grid -->
}
Use HTML Helpers in Templates
Templates can include Razor HTML helpers that render static content. The code below uses the ActionLink
HTML helper to render the same link across different template instances:
@(Html.DevExtreme().DataGrid()
.Columns(columns => {
//...
columns.Add().CellTemplate(@<text>
@Html.ActionLink("Link Text", "Details")
</text>);
})
)
Process Template Parameters with HTML Helpers
Create a custom HtmlHelper
extension to access template parameters in an HTML Helper.
The example below demonstrates how to use a custom HTML Helper to render a link with the OrderID
parameter.
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.IO;
using System.Text.Encodings.Web;
public static class TemplatedHtmlHelperExtensions {
public static IHtmlContent TemplatedHtmlHelper(this IHtmlHelper html, IHtmlContent template, Func<string, string> replacementFunc) {
using(var writer = new StringWriter()) {
template.WriteTo(writer, HtmlEncoder.Default);
return html.Raw(replacementFunc(writer.ToString()));
}
}
}
You can generate the same URL with HTML and a reference to the template parameter:
@(Html.DevExtreme().DataGrid()
.Columns(columns => {
columns.Add().CellTemplate(@<text>
<a href="@Url.Action("ActionName", "ControllerName")/<%- data.OrderID %>">Link Text</a>
</text>);
})
)