Customize Widget Element Appearance - MVVM Approach

You may often encounter the need to customize widget appearance. In the most simple cases, widget elements (title, content, collection item) have a simple textual presentation. But in most cases, widget elements require a more complex structure. Moreover, an element appearance may depend on values held in a data model associated with the current view. In this topic, you will learn how to customize the appearance of such widget elements.

If a widget contains elements available for customization, it includes the corresponding options that end with "Template". For instance, the Popover widget enables you to customize its content and title. For this purpose, it includes the contentTemplate and titleTemplate options.

Similar article is available for the jQuery approach.

Read below to learn how to customize the required element appearance.

Use a Default Template

A default template for a widget is defined out-of-the-box. Default templates are based on a predefined set of fields in the widget. For example, every widget has a field that allows you to modify textual representation of the widget.

  • text
    Specifies the text inserted into the widget element.

Different widgets can have other additional fields (for example, icon field).

Collection widgets have default templates for item representation.They are based on a predefined set of fields in the widget data source, requiring you to provide the required set of fields for your widget's data source, so that widget items are displayed using a default template. The following are the fields that are used in a default item template of any widget.

  • disabled
    Specifies whether or not the list item is disabled.
  • visible
    Specifies whether or not the list item is visible.
  • html
    Specifies the html code inserted into the item element.
  • template
    Specifies an item template that should be used to render this item only.
  • text
    Specifies the text inserted into the item element.

However, additional fields can be required for item templates of certain widgets. For instance, a default template for the List widget is based on the set of fields above. However, the key field is also required to specify the group to which an item is related. To learn what set of fields is required for a specific widget, refer to the Default Item Template reference section of this widget.

In certain scenarios, it is enough to specify a simple array as a widget data source. In this instance, a default item template contains text binding associated with the current array value.

Use Custom CSS styles

You can apply custom CSS styles to widget elements. For this purpose, assign a custom class name to the widget element and use this class name when defining styles for widget elements.

CSS
.custom-popup .dx-popup-title {
    padding: 0px 10px;
}
.custom-popup .dx-popup-title .dx-toolbar-label {
    font-size: 12px;
    text-transform: uppercase;
}
.custom-popup .dx-popup-content {
    background: lightgray;
}
AngularJS
HTML
<div dx-popup="popupOptions" class="custom-popup">
    Popup content
</div>
Knockout
HTML
<div data-bind="dxPopup: popupOptions" class="custom-popup">
    Popup content
</div>

Customize Rendered Markup Element

When a customizable widget element is rendered, the widget fires the corresponding event, which enables you to modify the rendered element for your requirements. You can assign the function which handles the required event to the onElementRendered option, where Element is a name of the rendered widget element. For instance, pass the event handling function to the onTitleRendered option to handle the event that occurs when the widget title is rendered. If a widget contains customizable content, the option holding a function called when widget content is rendered is called onContentReady.

JavaScript
var popoverOptions = {
    onTitleRendered: titleRenderedHandler
}

The object passed to the handler function enables you to access the rendered markup element and the data model associated with the current view.

JavaScript
var myTitle = "Popover Title";
var titleRenderedHandler = function(e) {
    // Use the 'e' object to access the widget markup element, rendered element and data model
    e.titleElement.append("<h1>" + myTitle + "</h1>");
}

Refer to the required event description for detailed information on the supported fields of the parameter object.

Note that rendered (for example onItemRendered, onGroupRendered) event handlers for collection items have other parameters. For more information, refer to the Customize Collection Item Appearance article.

See Also

Implement a Custom Template

To customize widget element appearance, you can use a built-in template engine.

In the examples presented below, the data model has the following structure.

AngularJS
JavaScript
function Controller($scope) {
    $scope.popoverTitle = "Popover Title";
}
Knockout
JavaScript
viewModel = {
    popoverTitle: "Popover Title"
}

To specify widget element structure, create an HTML container element within the widget container element and apply the data-options attribute set to dxTemplate. Then, insert the required structure in the newly added dxTemplate element.

AngularJS
HTML
<div dx-popover="{ showTitle: true }">
    <div data-options="dxTemplate:{ name:'title' }">
        <h1>{{popoverTitle}}</h1>
    </div>
</div>
Knockout
HTML
<div data-bind="dxPopover:{ showTitle: true }">
    <div data-options="dxTemplate:{ name:'title' }">
        <h1 data-bind="text: popoverTitle"></h1>
    </div>
</div>

A binding context of a template is the bound view or application model. So, you can bind template elements to the scope or view model's fields directly (see the code above). To access another binding context within a template, use the Knockout binding variables or AngularJS binding variables, depending on the approach you use.

In the Collection Widgets in AngularJS approach, to access item object's fields within a template, use a variable whose name is assigned to the dx-item-alias directive.

HTML
<div dx-list="{ dataSource: listData }" dx-item-alias="stateInfo">
    <div data-options="dxTemplate:{ name:'item' }">
        <h1>{{stateInfo.name}}</h1>
        <p><b>Capital</b>: <i>{{stateInfo.capital}}</i></p>
        <p><b>Area</b>: <i>{{stateInfo.area}}</i></p>
        <p><b>Population</b>: <i>{{stateInfo.population}}</i></p>
    </div>
</div>

The default name of the template element usually corresponds to the required element name (e.g., 'title' for a title element,'content' for a content element, 'item' for an item element). If you use a different template name, assign it to the appropriate option (titleTemplate for a title element, contentTemplate for a content element and so on).

AngularJS
HTML
<div dx-popover="{ showTitle: true, titleTemplate:'popoverTitle', contentTemplate: 'popoverContent' }">
    <div data-options="dxTemplate:{ name:'popoverTitle' }">
        ...
    </div>
    <div data-options="dxTemplate:{ name:'popoverContent' }">
        ...
    </div>
</div>
Knockout
HTML
<div data-bind="dxPopover:{ showTitle: true, titleTemplate:'popoverTitle', contentTemplate: 'popoverContent' }">
    <div data-options="dxTemplate:{ name:'popoverTitle' }">
        ...
    </div>
    <div data-options="dxTemplate:{ name:'popoverContent' }">
        ...
    </div>
</div>

You can assign the template name directly to the option, or assign a function that returns the required template name.

JavaScript
var popoverOptions = {
    contentTemplate: function() { 
        return 'popoverContent'; 
    }
}

Provide Several Custom Templates

You may have several templates defined within a widget. To apply the required one in a specific context, assign a function to the required "Template" option. The return value of this function must be a string representing the name of the required template.

AngularJS
JavaScript
function Controller($scope) {
    $scope.popoverTitle = "Popover Title";
    $scope.highlightTitle = false;
    $scope.getTemplate = function() {
        return highlightTitle ? "highlightedTitle" : "standardTitle";
    }
}
HTML
<div dx-popover="{ showTitle: true, titleTemplate: getTemplate }">
    <div data-options="dxTemplate:{ name:'standardTitle' }">
        <h1>{{popoverTitle}}</h1>
    </div>
    <div data-options="dxTemplate:{ name:'highlightedTitle' }">
        <h1 style="color: red;">{{popoverTitle}}</h1>
    </div>
</div>
Knockout
JavaScript
viewModel = {
    popoverTitle: "Popover Title",
    highlightTitle: false,
    getTemplate: function() {
        return highlightTitle ? "highlightedTitle" : "standardTitle";
    }
}
HTML
<div data-bind="dxPopover:{ showTitle: true, titleTemplate: getTemplate }">
    <div data-options="dxTemplate:{ name:'standardTitle' }">
        <h1 data-bind="text: popoverTitle"></h1>
    </div>
    <div data-options="dxTemplate:{ name:'highlightedTitle' }">
        <h1 style="color: red;" data-bind="text: popoverTitle"></h1>
    </div>
</div>

In the same manner, you can provide an individual template for an item of a collection widget. To set the required template for a widget item, specify the template field within the data source object that represents this item.

JavaScript
tileViewData = [
    {
        name: 'Alabama',
        area: 135765,
        population: 4822023,
        capital: 'Montgomery',
        //template to this certain item
        template: 'specific'
    },
    {
        name: 'Alaska',
        area: 1717854,
        population: 731449,
        capital: 'Juneau'
    },
    ...
];
AngularJS
HTML
<div dx-tile-view = "{ dataSource: tileViewData, itemTemplate:'myItem' }" dx-item-alias="stateInfo">
    <div data-options="dxTemplate:{name:'myItem'}">
        ...
    </div>
    <div data-options="dxTemplate:{name:'specific'}">
        ...
    </div>
</div>
Knockout
HTML
<div data-bind="dxTileView:{dataSource: tileViewData, itemTemplate:'myItem'}">
    <div data-options="dxTemplate:{name:'myItem'}">
        ...
    </div>
    <div data-options="dxTemplate:{name:'specific'}">
        ...
    </div>
</div>

If you need to define individual markup for collection widget items, which are not bound to a data source, you may use the dxItem markup component.

AngularJS
HTML
<div dx-list="listOptions" dx-item-alias="stateInfo">
    <div data-options="dxItem: item1Options">
        <!--First item markup-->
    </div>
    <div data-options="dxItem: item2Options">
        <!--Second item markup-->
    </div>
    <div data-options="dxItem: item3Options">
        <!--Third item markup-->
    </div>
    . . .
</div>
Knockout
HTML
<div data-bind="dxList: listOptions">
    <div data-options="dxItem: item1Options">
        <!--First item markup-->
    </div>
    <div data-options="dxItem: item2Options">
        <!--Second item markup-->
    </div>
    <div data-options="dxItem: item3Options">
        <!--Third item markup-->
    </div>
    . . .
</div>

Provide a Common Template

When you have several widgets with similar elements, you may need to define a common custom template for them. For this purpose, factor out a template into a separate element, as demonstrated below.

AngularJS
JavaScript
function Controller($scope) {
    $scope.name = "John Doe";
    $scope.city = "Glendale";
    $scope.phone = "(626) 555-9248";
}
HTML
<script id="person-template">
    <h3>{{name}}</h3>
    <p>City: <span>{{address}}</span></p>
    <p>Phone: <span>{{phone}}</span></p>
</script>
Knockout
JavaScript
var viewModel = {
    name: "John Doe",
    city: "Glendale",
    phone: "(626) 555-9248"
}
HTML
<script id="person-template">
    <h3 data-bind="text: name"></h3>
    <p>City: <span data-bind="text: address"></span></p>
    <p>Phone: <span data-bind="text: phone"></span></p>
</script>

To use the common template for the rendering of a certain element, assign one of the following values to the appropriate "Template" option of the widget.

  • Assign a jQuery object of the template's container.

    AngularJS
    HTML
    <div dx-popover="{ contentTemplate: $('#person-template') }">
    </div>
    Knockout
    HTML
    <div data-bind="dxPopover:{ contentTemplate: $('#person-template') }">
    </div>
  • Assign a DOM Node of the template's container.

    Knockout
    HTML
    <div data-bind="dxPopover:{ contentTemplate: document.getElementById('person-template') }">
    </div>
    AngularJS
    HTML
    <div dx-popover="{ contentTemplate: document.getElementById('person-template') }">
    </div>
  • Assign a function that returns the jQuery object or a DOM Node of the template's container.

    AngularJS
    HTML
    <div dx-popover="{ contentTemplate: function() { return document.getElementById('person-template'); } }">
    </div>
    Knockout
    HTML
    <div data-bind="dxPopover:{ contentTemplate: function() { return document.getElementById('person-template'); } }">
    </div>

To use the common template for the item rendering of a collection widget, assign a jQuery object, a DOM node of the template element, or a function returning any of them to the itemTemplate option.