Skip to main content

Create a Data-Aware Item for the Web Dashboard

  • 11 minutes to read

Important

A custom item is an independent module called an extension. If you are not familiar with the basic concepts of extensions, please review the following topic before you continue: Extensions Overview.

In the previous lesson, you created a custom item that displays text and added a custom property that allows you to change this static text.

This tutorial explains how to create a custom item that is bound to data, and how to display data from a data source. This custom item displays formatted dimension values and allows users to color these values. The custom item also contains an additional option that allows users to change the item’s background color.

DataAwareItem_Main

You can download the ready-to-use projects based on the Create a custom item tutorials:

View Example: ASP.NET Core View Example: React

Note

For another example of the basic Dimension and Measure implementation, view the Simple Table item in the Custom Item Gallery:

View Example: ASP.NET Core View Example: Angular View Example: React

Prerequisites

A custom item script depends on the platform you use:

Module script
Client components (Angular, React, Vue) use imports and classes to define a custom item.
Classic script
A script for the ASP.NET Web Forms, ASP.NET MVC, ASP.NET Core, BLazor, and JavaScript controls encapsulates a custom item in the IIFE function expression.

Before you begin, create a Web Dashboard project for the required platform.

Create an External Script

In your project, create an external DataAwareItem.js file, so you can reuse the created extension in other Web Dashboard applications.

Define a class that will be a custom item (DataAwareItem).

import { CustomItemViewer, ResourceManager } from 'devexpress-dashboard/common'
import { CustomItem } from 'devexpress-dashboard/model'
import { FormItemTemplates } from 'devexpress-dashboard/designer'
class DataAwareItem {
}

export default DataAwareItem;

Warning

If you use the Classic script, place the code below inside the self-invoking function.

Define a Toolbox Icon

In the DataAwareItem.js file, add a 24x24 SVG icon as a string variable:

var svgIcon = '<svg id="dataAwareItemIcon" viewBox="0 0 24 24"><path stroke="#ffffff" fill="#4842f4" d="M12 2 L2 22 L22 22 Z" /></svg>';    

The icon will be used to display the custom item in the Toolbox:

CustomItem_DataAware_Toolbox

Specify the Custom Item’s Settings

Implement the ICustomItemMetaData interface to define this custom item’s settings:

  • In the bindings option, configure a dimension to bind a custom item to data. Implement the ICustomItemBinding interface and create an object that defines a dimension. Include the enableColoring option to specify that the created dimension supports coloring.
  • In the icon option, pass the SVG icon’s id (dataAwareItemIcon).
  • In the title option, specify the text displayed in the dashboard item caption and as the Toolbox element’s tooltip (Data Aware Item).

As a result, the Binding menu contains the Dimension section, where a user can add one dimension from a data source:

web-data-aware-custom-item-data-item-menu

Use the ICustomItemMetaData.customProperties and ICustomItemMetaData.optionsPanelSections properties to define a custom option that allows users to change the item’s background color:

DataAwareItem_BackColorProperty

var dataAwareItemMetaData = {
    bindings: [{
        propertyName: 'dimensionValue',
        dataItemType: 'Dimension',
        displayName: 'Dimension',
        enableColoring: true
    }],
    customProperties: [{
        owner: CustomItem,
        propertyName: 'backColorProperty',
        valueType: 'string',
        defaultValue: 'None'
    }],
    optionsPanelSections: [{
        title: 'Background',
        items: [{
            dataField: 'backColorProperty',
            label: { text: 'Backcolor' },
            template: FormItemTemplates.buttonGroup,
            editorOptions: {
                items: [{ text: 'None' }, { text: 'Red' }, { text: 'Blue' }]
            }
        }]
    }],
    icon: 'dataAwareItemIcon',
    title: 'Data Aware Item'
};

Implement Custom Item Rendering

The CustomItemViewer class specifies visual representation of the custom item. Override the CustomItemViewer.renderContent method to display custom item content.

Create methods that allow you to display dimension values from a data source and implement the following logic for a custom property:

_getDataSource
The _getDataSource method returns data displayed in the custom item. The iterateData method generates data rows for the custom item. When a user binds the custom item to a data field and enables coloring, the iterateData method is called for each row in the aggregated data. This method accepts a function as a parameter and allows you to iterate through aggregated data and obtain required values (dimension or measure values, display text, colors, and more). In this data-aware item, the iterateData method obtains display text and the color for the dimensionValue data item (the getDisplayText and getColor methods). The enableColoring option enabled in the metadata indicates that dimension values can be colored.
_getBackColorProperty
The _getBackColorProperty method changes the background color according to the Options | Background | Backcolor custom UI option. Use the CustomItemViewer.getPropertyValue method to get the value of the created custom option and change the CSS style of the background HTML element according to the returned value.

Note

Do not set IDs for DOM elements in the CustomItemViewer.renderContent method call. When the custom item is maximized, the renderContent method is called again and creates one more DOM element with the same ID. If you create an element inside this method, the element ID will not be unique on the page.

import { CustomItemViewer, ResourceManager } from 'devexpress-dashboard/common'
import { CustomItem } from 'devexpress-dashboard/model'
import { FormItemTemplates } from 'devexpress-dashboard/designer'
// ...
class DataAwareItemViewer extends CustomItemViewer {
    constructor(model, $container, options) {       
        super(model, $container, options);
    }
    renderContent(element, changeExisting) {
        while (element.firstChild)
            element.removeChild(element.firstChild);
        var clientData = this._getDataSource();
        clientData.forEach(function (item) {
            var div = document.createElement('div');
            div.style.color = item.color;
            div.innerText = item.dimensionDisplayText;
            element.appendChild(div);
        });
        element.style.background = this._getBackColorProperty();
    };

    _getDataSource() {
        var clientData = [];
        this.iterateData(function (dataRow) {
            clientData.push({
                dimensionDisplayText: dataRow.getDisplayText('dimensionValue')[0] || "",
                color: dataRow.getColor()[0]
            });
        });
        return clientData;
    };

    _getBackColorProperty() {
        switch (this.getPropertyValue('backColorProperty')) {
            case 'None': return "rgb(255,255,255)";
            case 'Red': return "rgb(255,220,200)";
            case 'Blue': return "rgb(135,206,235)";
        }
    };
}

Create an Extension

The ICustomItemExtension interface allows you to define a custom item as an extension.

import { CustomItemViewer, ResourceManager } from 'devexpress-dashboard/common'
import { CustomItem } from 'devexpress-dashboard/model'
import { FormItemTemplates } from 'devexpress-dashboard/designer'
// ...
class DataAwareItem {
    constructor(dashboardControl) {
        ResourceManager.registerIcon(svgIcon);    
        this.name = "dataAwareItem";
        this.metaData = dataAwareItemMetaData;
    }

    createViewerItem(model, $element, content) {
        return new DataAwareItemViewer(model, $element, content);
    }
}

export default DataAwareItem;

The complete extension code:

Show code
// #region imports
import { CustomItemViewer, ResourceManager } from 'devexpress-dashboard/common'
import { CustomItem } from 'devexpress-dashboard/model'
import { FormItemTemplates } from 'devexpress-dashboard/designer'
// #endregion
// #region svgIcon
var svgIcon = '<svg id="dataAwareItemIcon" viewBox="0 0 24 24"><path stroke="#ffffff" fill="#4842f4" d="M12 2 L2 22 L22 22 Z" /></svg>';    
// #endregion
// #region metadata
var dataAwareItemMetaData = {
  bindings: [{
      propertyName: 'dimensionValue',
      dataItemType: 'Dimension',
      displayName: 'Dimension',
      enableColoring: true
  }],
  customProperties: [{
      owner: CustomItem,
      propertyName: 'backColorProperty',
      valueType: 'string',
      defaultValue: 'None'
  }],
  optionsPanelSections: [{
      title: 'Background',
      items: [{
          dataField: 'backColorProperty',
          label: { text: 'Backcolor' },
          template: FormItemTemplates.buttonGroup,
          editorOptions: {
              items: [{ text: 'None' }, { text: 'Red' }, { text: 'Blue' }]
          }
      }]
  }],
  icon: 'dataAwareItemIcon',
  title: 'Data Aware Item'
};
// #endregion
// #region viewer
class DataAwareItemViewer extends CustomItemViewer {
  constructor(model, $container, options) {       
        super(model, $container, options);
  }
    renderContent(element, changeExisting) {
        while (element.firstChild)
            element.removeChild(element.firstChild);
        var clientData = this._getDataSource();
        clientData.forEach(function (item) {
            var div = document.createElement('div');
            div.style.color = item.color;
            div.innerText = item.dimensionDisplayText;
            element.appendChild(div);
        });
        element.style.background = this._getBackColorProperty();
    };

    _getDataSource() {
        var clientData = [];
        this.iterateData(function (dataRow) {
            clientData.push({
                dimensionDisplayText: dataRow.getDisplayText('dimensionValue')[0] || "",
                color: dataRow.getColor()[0]
            });
        });
        return clientData;
    };

    _getBackColorProperty() {
        switch (this.getPropertyValue('backColorProperty')) {
            case 'None': return "rgb(255,255,255)";
            case 'Red': return "rgb(255,220,200)";
            case 'Blue': return "rgb(135,206,235)";
        }
    };
}
// #endregion
// #region createItem
class DataAwareItem {
    constructor(dashboardControl) {
        ResourceManager.registerIcon(svgIcon);    
        this.name = "dataAwareItem";
        this.metaData = dataAwareItemMetaData;
    }

    createViewerItem(model, $element, content) {
        return new DataAwareItemViewer(model, $element, content);
    }
}

export default DataAwareItem;
// #endregion 

Register the Custom Item as an Extension

Attach the created DataAwareItem.js script file to the page containing the Web Dashboard code. The external script you created is now available in the application.

You need to register the extension before the control is rendered. Refer to the following topics for information on how to get access to the DashboardControl instance and customize it before any element in the Web Dashboard control has been rendered:

Register the created extension in the DashboardControl.registerExtension method call:

function onBeforeRender(e) { 
  var dashboardControl = e.component;
  dashboardControl.registerExtension(new DashboardPanelExtension(dashboardControl));
  dashboardControl.registerExtension(new HelloWorldItem(dashboardControl));
  dashboardControl.registerExtension(new DataAwareItem(dashboardControl));
  // ...
}

Result

Run the project and click the Data Aware Item Toolbox item to add the custom item to the dashboard:

CustomItem_DataAware_Toolbox

This action adds the empty item to the dashboard.

DataAwareItem_Empty

Invoke the Binding menu, click Set Dimension, and select the ProductName field:

DataAwareItem_Bound

Use Options | Coloring to enable coloring for dimensions:

DataAwareItem_Colored

Go to Options | Background and use the Backcolor custom option to change the item’s background color:

DataAwareItem_BackColorProperty

In the next lesson, you will create a more “real-world” custom item that uses an external visualization widget that supports data binding, master filtering, and coloring.