Skip to main content

Grid Widget

Easy to use, fully featured grid widget with state formatting to view information at a glance, based on the Tabulator library.

Usage

The IQNOX Grid Widget is a widget built from the ground up with performance and customization in mind. With features like: cell state formatting, in-cell editing, in-cell mashups, custom columns and more.

The key features that make the IQNOX Grid Widget great:

  • An easy UI to configure columns and a purposely built configurator for styling the look and feel of the widget
  • Full customization per column. Each column can look totally different from another
  • State formatting on entire rows with a fully built in query builder
  • State formatting on cells. Cells can have a custom label template which be customized based on value with state formatting
  • Support for remote data. No need to output all the data from your server anymore. Using pagination, the service can be built to only get data for the current page
  • Freeze columns at the beginning or end of the grid
  • Enable different type of filters per columns
  • Different selection modes, single, multiple by clicking the row or by enabling selection from checkbox at the beginning of the row
  • Enable sorting on desired columns
  • Add custom columns that are not present in the DataShape
  • Support for in cell mashups. Each cell can display a mashup that inherits the Data from the widget
  • Custom column renderer. The ability to render anything in a grid cell

Grid Example

Properties

PropertiesTypeBindingDefaultDescription
CustomClassSTRINGEnables you to define an html class to the top div of the widget. Multiple classes can be entered, separated by space.
DataINFOTABLE<Infotable with data to be displayed in the grid
AllowColumnReorderBOOLEANFALSEAllow the user to reorder the columns in the grid at runtime
AllowSelectWithCheckboxBOOLEANFALSEAllow the user to select rows at runtime using checkboxes
PersistenceIdSTRINGIQNOX grid can store a variety of table setup options so that each time a user comes back to the page, the table is laid out just as they left it. Allows to enable/disable persistance on grid. If an id is set, persistance will be enabled. The id must be unique so the grid can be identified at runtime when there are multiple of them.
PersistenceSettingsJSONGrid persistence settings.
DataIdSTRINGThe infotable field which represents the data id used by the grid
EditedDataINFOTABLE>Outputs the edited data in the grid.
MultiColumnSortOrderSTRING<Set the default multi-column sorting using the column field names: name:asc,value:desc. The priority between them is the order you define them in.
AllowEditBOOLEAN<Enable/Disable grid edit options from column configurator.
MinimumItemsSelectedNUMBER0Minimum items of selected items
MaximumItemsSelectedNUMBER0Maximum items of selected items
LayoutSTRINGfitDataFillChange how columns will fit inside your grid container.
ExportFileNameSTRINGDataExportFileName: Filename for all the grid exports. Developers should avoid using unsupported files name characters based on the target OS.
ShowExportToCSVBOOLEANTRUEShows export option into the grid settings menu at runtime
ShowExportToJSONBOOLEANTRUEShows export option into the grid settings menu at runtime
ShowExportToPDFBOOLEANFALSEShows export option into the grid settings menu at runtime
ShowExportToXLSXBOOLEANFALSEShows export option into the grid settings menu at runtime
DefaultSelectedRowSTRING<Specifies the row number to be selected on grid load. Specific rows can be selected separated by a comma: 2, 5, 7. Or numeric ranges: 1-6.
MovableRowsBOOLEANFALSEAllow the user to move the rows in the grid at runtime
HasSelectionBOOLEAN>FALSEAllows the user to take some actions if grid has a selection active or not.
AutoScrollBOOLEAN<TRUEEnable/Disable auto scroll. Scrolls to the selected row when selected row changes or window is resized.
IsEditingBOOLEAN>FALSEOutputs whether the grid widget is in editing mode
NumberOfSelectedRowsNUMBER>Outputs the number of selected rows
HasRowsBOOLEAN>Outputs if grid have bound rows
NumberOfRowsNUMBER>Outputs the total number of rows
ColumnsRuleSetJSON<The rule set for columns state formatter. This is not expected to be changed manually, column configurator should be used instead.
GridConfigurationJSON<Saved configuration used for columns. This is not expected to be changed manually, column configurator should be used instead.
AutomaticRemoteDataBOOLEANTRUEChose if bindings need to be created to load the remote data, or if the bound service is automatically called. See docs for limitations.
FilterAndSortModeSTRINGLocalHow the filtering and sorting should be done, locally, or on the server.
PaginationModeSTRINGDisabledHow paginated data should be loaded(disabled, localPagination, remotePagination, remoteProgressiveLoad).
SelectedRowsINFOTABLE>Currently selected rows in the table. Useful when remote pagination is enabled
QueryQUERY<>When FilterAndSortMode, is set to remote, contains the query the user has built by sorting and filtering the table
PageRowOffsetNUMBER>When pagination is enabled, the offset of the first row shown.
ProgressiveLoadScrollMarginNUMBERWhen pagination is set to progressiveLoad, when to trigger a new page.
PageRowSizeNUMBER>When pagination is enabled, the number of rows shown on the page.
PageTotalRowCountNUMBER<When PaginationMode is set to remote, the total number of rows be known.
UserPreferencesJSON<>Settings the user has done to the grid to be saved.

Services

PropertyTypeBindingDescription
SelectAllSERVICE<Select all rows in the grid.
DeselectAllSERVICE<Deselect all rows in the grid.
DownloadAsCsvSERVICE<Download grid data as CSV.
DownloadAsJsonSERVICE<Download grid data as JSON.
DownloadAsXlsxSERVICE<Download grid data as XLSX.
EditModeStartSERVICE<Start edit mode on the grid.
EditModeFinishSERVICE<Finish edit mode on the grid.
ResetGridSERVICE<Resets the grid filters, sorters and pagination.

Events

PropertyTypeBindingDescription
RowClickedEVENT>Triggers when row is clicked
SelectedRowsChangedEVENT>Triggers when table row selection is changed.
EditFinishedEVENT>Triggers when table cell edit is finished.
QueryChangedEVENT>When FilterAndSortMode, is set to remote, fires when the user changes the filters and sorters on the data. New data must be bound into the Data infotable.
PageRequestedEVENT>When PaginationMode is set to remote, fires when a new page is requested to be loaded in the gridchanged.
UserPreferencesChangedEVENT>Triggers when the user makes a change to the grid settings.

Grid Column Configurator

Default Configuration

When data is bound to the widget, a default configuration is created based on the bound data. The grid widget can be used and its fully functional without changing anything from the default state.

Every change to the used DataShape will be reflected into the grid column configuration.

Grid configuration will be fully reset to default every time the binding is changed

Custom Configuration

Grid is using our new column configurator for customization like enabling sorters, header filters reordering column, show/hide columns. Alt text

  • Columns: Columns name and baseType

  • Include: If true, column is included in the runtime column visibility menu(Right click on grid columns in header) Alt text

  • Show: If true, column will be visible at runtime

By selecting a column from the left, you have access to configure column settings for the selected column.

Columns defied in the DataShape can be restored to default values by clicking the reset button from the top right corner of the column configurator tab.

Add custom columns

Column configurator can be used to add custom columns to display mashups or custom renderers. These columns are not bound to any specific field, but they do have access to the entire Data.

Custom column

Column settings

  • General:

    • DataShape field: Field name from the DataShape used for grid Data INFOTABLE.
    • Identifier: Column unique identifier(only for custom columns)
  • Format:

    • Title: Title of the column, shown in the headers and visibility menu.
    • Width: Sets the width of this column, this can be set in pixels or as a percentage of total table width (if not set the system will determine the best).
    • Auto width: Automatically assign a width to the column that makes the entire contents fit.
    • Minimum/Maximum width: Minimum/maximum width of the column, this should be set in pixels.
    • Header alignment: Sets the horizontal alignment of the header text.
    • Cell alignment: Sets the horizontal alignment of the cell text.
    • Enable sorting: Sets if the user can sort this column by clicking on the header. This will also show/hide the sort icon.
    • Enable header filter: Sets if the user can filter the column by using a header filter.
      • Header filter: Header filter type
      • Filter placeholder: Placeholder
    • Freeze column: Sets if the column is frozen, so during horizontal scrolling, the column will always be visible.
  • Renderer:

    • Cell renderer: Setting describing how each column should be rendered
    • Template: Template selector for renderers that supports this option.
      • Example: String will render an IQNOX Label widget, which can use any of the Templates for that widget
    • Format: Will use Format Complex
    • Mashup: Mashup selector for renderers that support this option
    • Max width: Max width for renderers that support this option
    • Max height: Max height for renderers that support this option
  • Editor:

    • Editor type: Setting describing how each column should be edited
    • Template: Template selector
    • Dropdown JSON values: values displayed in dropdown formatted as a json
      • Example:
    • Input type: Input type(text only)
note

When String renderer is selected and column baseType is boolean, some extra options are available in Format section:

  • Value when true: Applies for a column with the baseType set to BOOLEAN. Represents the value to be shown when the boolean is true.`
  • Icon when true: Applies for a column with the baseType set to BOOLEAN. Represents the icon to be shown when the boolean is true
  • Value when false: Applies for a column with the baseType set to BOOLEAN. Represents the value to be shown when the boolean is false
  • Icon when false: Applies for a column with the baseType set to BOOLEAN. Represents the icon to be shown when the boolean is false
  • Show only icon: Applies for a column with the baseType set to BOOLEAN. If only the icon should be shown

User preferences

User preferences can be used to save different configurations used with the grid widget such as column visibility and position, sorting, page number and filters. For this, a new property called userPreferences was added in PersistenceSettings which can be set as local, where the configuration is saved in the browser and can only be used locally, or as external. If userPreferences is set to external, a new property called UserPreferences becomes available, which can be bound to the grid to load saved configuration or saved externally, also an event called UserPreferencesChanged will be available which is triggered when the UserPreferences changes

note

PersistenceSettings property

Alt text

Renderer types

The grid data can be displayed in various forms that can be chosen from column configurator in the renderer section

String renderer
The data will be displayed using IQNOX Label widget. If you are using this renderer, the text can be styled using existing templates defined for the IQNOX Label widget, also formatting can be applied on this type of renderer by using State formatting section.

String renderer

String renderer object structure

  StringCellRenderer {
cellRenderer: 'string';
/**
* Allows the user to specify a formatting string to use to render the value
*/
format?: string;
/**
* Applies for a column with the `baseType` set to BOOLEAN. Represents the value to be shown when the boolean is `true`
*/
valueWhenTrue?: string;
/**
* Applies for a column with the `baseType` set to BOOLEAN. Represents the icon to be shown when the boolean is `true`
*/
iconWhenTrue?: string;
/**
* Applies for a column with the `baseType` set to BOOLEAN. Represents the value to be shown when the boolean is `false`
*/
valueWhenFalse?: string;
/**
* Applies for a column with the `baseType` set to BOOLEAN. Represents the icon to be shown when the boolean is `false`
*/
iconWhenFalse?: string;
/**
* Applies for a column with the `baseType` set to BOOLEAN. If only the icon should be shown
*/
showOnlyIcon?: boolean;
/**
* Represents the name of IQNOX Template to be used to render the value
*/
template?: string;
}
Markdown renderer
This can be used to render markdown inside the grid cell that enables rich text formatting like bold, underline etc.

Markdown renderer

Markdown renderer object structure

  MarkdownCellRenderer {
/**
* Renders the value as markdown text, that is rendered inside the cell. The generated HTML is sanitized
*/
cellRenderer: 'markdown';
}
Html renderer
This can be used to render HTML inside the grid cell, the html code is sanitized

Html renderer

Html renderer object structure

  HtmlCellRenderer {
/**
* Renders the value as a HTML string. This value is sanitized prior to being rendered.
*/
cellRenderer: 'html';
}
Hyperlink renderer
This can be used to render a hyperlink inside the grid cell

Hyperlink renderer

Hyperlink renderer object structure

  HyperlinkCellRenderer {
/**
* Renders the value as a hyperlink, allowing the user to click on the value to open a new tab
*/
cellRenderer: 'hyperlink';
}
Mashup renderer
This renderer can be used to render a mashup inside the grid cell. The mashup will have access to the row data by setting a INFOTABLE parameter on the mashup called Data that can be used and bound inside the used mashup. Using this type of renderer requires cell width and height to be set to fit the mashup

Mashup renderer

Mashup renderer object structure

  MashupCellRenderer {
/**
* Renders the value in a ThingWorx mashup, that takes an input parameter the entire infotable row
*/
cellRenderer: 'mashup';
/**
* Represents the ThingWorx mashup name to use.
* The mashup should have a parameter of type INFOTABLE named Data that will contain the full row values.
*/
mashup?: string;
}
Image renderer

This renderer can be used to render an image inside the grid cell. Max width and height must be specified.


Image renderer

Image renderer object structure

ImageCellRenderer {
/**
* Renders that the value as an hyperlink to an image that is then rendered inside the cell
*/
cellRenderer: 'image';

/**
* Applies for the `image` `cellRenderer`, describes the dimensions of the rendered image
*/
maxWidth: {
value: string | number;
unit?: string;
};
/**
* Applies for the `image` `cellRenderer`, describes the dimensions of the rendered image
*/
maxHeight: {
value: string | number;
unit?: string;
};
}
Custom renderer

This renderer allows you to write a custom javascript function to render a column. Only the function body can be modified and must be returned a string or HTMLElement. No validation or sanitization done on the input, but it'a available in the scope for use(docs).

See the following references for documentation and examples:


Custom Renderer

Custom renderer object structure

   CustomCellRenderer {
/**
* Renders the value using an actual typescript function that the user can write in
*/
cellRenderer: 'custom';

/**
* Actual code that should be executed at runtime to render the column
*/
javascriptCode: string;

/**
* The code that the user has entered to render this column.
* This code gets transpiled into javascript and is stored on the {@link javascriptCode} property.
*/
typescriptCode?: string;
}

Editor types

The grid data can be edited in various forms that can be chosen from column configurator in the editor section.

Input editor
This can be used to edit grid data using an input element

Input editor

Input editor object structure

InputCellEditor {
/**
* Renders a cell editor using an text input
*/
editorType: 'text';
/**
* Represents the name of an IQNOX Template to use to render the value
*/
template?: string;
/**
* Applies for `text` editors. The type of input to use where the user should enter the value
*/
inputType?: 'text' | 'number' | 'datetime-local' | undefined;
}
Checkbox editor
Checkbox editor can be used to edit boolean values

Checkbox Editor

Checkbox editor object structure

 CheckboxCellEditor {
/**
* Renders a cell editor using a checkbox input.
*/
editorType: 'checkbox';
/**
* Represents the name of an IQNOX Template to use to render the value
*/
template?: string;
}
Dropdown editor
Dropdown editor can be used to edit grid data by selecting an option from data already existing in the dataset on that column, or using a custom data JSON defined in column configurator

Dropdown editor

Dropdown editor object structure

DropdownCellEditor {
/**
* Renders a cell editor using a dropdown.
*
* Values in the dropdown can either be static, or driven from the distinct values in the dataset
*/
editorType: 'dropdown';
/**
* Represents the name of an IQNOX Template to use to render the value
*/
template?: string;
/**
* Allows the specification a given list of values in a dropdown that the user can pick from.
* Stores a JSON representation of an array of objects with two keys: value(string), display(string).
* Follows this spec:
* ```ts
* { value: string; display: string }[]
* ```
*/
dropdownOptions?: string;
}

Column state formatting

Columns also supports State formatting(only for string renderer) individually, by selecting the State formatting menu from the top.

Alt text

Creating custom configuration object

Grid column configuration object can be manually created using the code editor embed into the property editing modal.

Configuration object structure

{
/**
* The schema of the configuration
*/
$schema: string;
/**
* Configuration of the columns.
* For each column, where the data comes from, and how it's rendered.
*/
columns: GridColumnConfiguration[];
}
Grid column configuration

A JSON schema is available after you import the widget into your ThingWorx environment, and include the path where developer can find it at.

If Monaco editor is setup, it will provide hints while editing the config.


Columns object structure

GridColumnConfiguration {
/**
* Name of the field, from the original DataShape that describes this grid column.
* This should be an unique identifier of the field.
*/
field: string;
/**
* Default visibility of the column.
*/
visible: boolean;
/**
* Set to `true` if the field should be included to be shown at runtime, or to `false` to completely exclude it
*/
include: boolean;
/**
* ThingWorx base type of the field this column represents.
*/
baseType: TWBaseType;
/**
* Can the cell be edited
*/
allowEdit: boolean;
/**
* Describes how the column should be formatted.
*/
format: {
/**
* Title of the column, shown in the headers and configuration menu.
*/
title: string;
/**
* Sets the width of this column, this can be set in pixels or as a percentage of total table width (if not set the system will determine the best).
*/
width: {
value: string;
unit?: string;
};
/**
* Automatically assign a width to the column that makes the entire contents fit.
*/
autoWidth: boolean;
/**
* Sets the minimum width of this column, this should be set in pixels.
*/
minimumWidth?: number;
/**
* Sets the maximum width of this column, this should be set in pixels.
*/
maximumWidth?: number;
/**
* Sets the horizontal alignment of the header text.
*/
headerAlignment: 'flex-start' | 'center' | 'flex-end';
/**
* Specifies how each cell in the column is aligned on the horizontal axis.
*/
cellAlignment: 'flex-start' | 'center' | 'flex-end';
/**
* Sets if the user can filter the column by using a header filter.
*/
allowHeaderFilter: boolean;
/**
* Type of header filter to be used.
* - `input`: Allow the user to type in text
* - `list`: Generates a list of selectable entities based on the data
* - `checkbox`: Helpful for boolean columns, filter rows based on true/false
* - `number`: For numeric columns, allows for filtering for based on comparison (see `headerFilterFunction`)
*/
headerFilter: 'input' | 'list' | 'tickCross' | 'number';
/**
* If you want to specify the type of filter used you can pass it to the headerFilterFunc option in the column definition object. This will take any of the standard filters outlined above or a custom function
*/
headerFilterFunction?: '>=' | '<=' | '=' | '>' | '<' | undefined;
/**
* Placeholder text for the header filter.
*/
filterPlaceholder?: string;
/**
* Sets if the user can sort this column by clicking on the header.
*/
allowHeaderSort: boolean;
/**
* Sets if the column is frozen, so during horizontal scrolling, the column will always be visible.
*/
frozenColumn: boolean;
};
/**
* Setting describing how each column should be rendered
*/
renderer:
| StringCellRenderer
| MashupCellRenderer
| MarkdownCellRenderer
| HtmlCellRenderer
| ImageCellRenderer
| HyperlinkCellRenderer
| CustomCellRenderer
/**
* Describes settings related to how the cell is being edited
*/
editor?: InputCellEditor | CheckboxCellEditor | DropdownCellEditor;
}

Each renderer has its own properties that can be specified

Each editor has its own properties that can be specified

Sorting

Sorting is enabled on all columns, this can be changed from grid column configurator for each column individually.

Default multi select order can be configured from widget properties (MultiColumnSortOrder), See properties

Filtering

IQNOX Grid allows you to filter the table data by any field in the data set.

Available filters:

  • Input - Text filtering
  • Number - Numbers filtering
  • List - Allow to select one or more field from the column to search for
  • Checkbox - For boolean values

Server side data

The grid widget supports dynamically loading of data form the server using services. The following use-cases are supported:

  • Remote pagination (the server paginates the data and just gives the frontend "slices"). UX-wise this can be presented as:
    • infinite scrolling
    • actual pagination where the users actually selects the page
  • Remote filtering and sorting:
    • The header filter and the sorting that the user does gets converted into a ThingWorx Query that the backend applies, and returns the matching data.
note

Note that these capabilities can be used at the same time.

The following properties are added and can be used:

  • FilterAndSortMode: 'local' | 'remote': Describes how filtering and sorting is done. Local means that it's done locally, using only the data present on the frontend. Remote means it's done on the server, and it's the service responsibility to filter and sort the data.
  • PaginationMode: 'disabled' | 'localPagination' | 'remotePagination' | 'remoteProgressiveLoad'.
  • If PaginationMode == 'remoteProgressiveLoad': ProgressiveLoadScrollMargin:
    • SelectedRows: INFOTABLE: The currently selected rows, especially important in a remote pagination.
    • SelectedRowsChanged: Event: Triggered when the user changes the selected rows.
    • ResetGrid: Service: Resets the grid filters, sorters and pagination.

There are two option in regard to how remote data can be configured.

Automatic remote data

With this option set to true, only one binding is needed, but the data service needs to follow some predefined formats. Essentially, it presents some opinionated defaults that the service implementer must follow. The advantage of using this approach is the simplicity of the mashup bindings.

The grid widget then will independently and automatically call the service with the correct parameters in order to retrieve data, without any extra bindings when the user interacts with the grid.

In order to configure remote data, the following must be done:

  1. Create a service that returns data as an INFOTABLE with two columns, in the following format. Note that the actual property names can be updated below.

    • totalRowCount: INTEGER: Total number of rows in this dataset
    • data: INFOTABLE: Actual data
  2. The service has the following input parameters (at a minimum). Not that the actual parameter names can be updated below.

    • query: QUERY: A query built out of the grid sorters and filters, to get a specific view on the dataset.
    • offset: INTEGER: Offset of items to get. For pagination, this would be currentPageNumber / pageSize
    • pageSize: INTEGER: Number of rows to retrieve.
  3. Bind the nested data in the service to the grid Data property, and configure its columns

    • Configure the RemotePropertyDataMap property. This allows remapping of the properties in the service output and input. By default this has value:
      {
    "totalRowCount": "totalRowCount",
    "data": "data",
    "query": "query",
    "offset": "offset",
    "pageSize": "pageSize"
    }
  4. At runtime, the grid can figure out the "Data" binding, and automatically call the service when needed.

Manual bindings

There is no magic, the grid exposes properties and events that the developer has to bind to their services. More work is required, but enables using the grid in all scenarios.

Sorters and filters

To remote support sorters and filters the following properties and events are added:

  • Query: QUERY, binding source: A Thingworx QUERY object built out of the sorters and filters from tabulator, in the data-loading event.
  • QueryChanged: TWEvent, binding source: Event that fires when the sorters or filters have changed.

The developer would use these to bind to their data service and show updated data whenever necessary.

Pagination (or progressive loading)

The following properties and events are added:

  • PageRowOffset: INTEGER, binding source: the offset to show rows from
  • PageRowSize: INTEGER, binding source: Number of rows to be shown on a page
  • PageRequested: TWEvent, binding source: Event that fires when the user has requested a new page, (with PageSize rows, offset at CurrentPage)
  • PageTotalRowCount: binding target: Total number of rows available

For pagination to work, TotalRowCount must be bound, and updated whenever the number of rows shown changes (e.g. on filtering).

The developer would add the data service once, and will create bindings that it both initially, to load the grid data, but also for any grid generated events (QueryChanged and PageRequested).

Bindings example:

The following example showcases the bindings that must be done to configure remote pagination, sorters and filtering. In this example, the data in the grid is completely reset when a Button widget is clicked. The data source for the grid is a service, Things.DataService that returns an infotable with two fields: totalRows and data. However, the same could be used using two separate services, one that returns the total number of rows, and other to return the data.

  • Bind an event to the service that should invoke the service: Button.Clicked -> Invoke Things.DataService
  • Bind the data into the grid: Things.DataService.result.data -> Grid.Data
  • Bind the total number of rows into the grid: Things.DataService.result.totalRows -> Grid.PageTotalRowCount
  • Bind the query generated by the grid into the service: Grid.Query -> Things.DataService.params.query
  • Bind the event fired when the grid query changes to invoke the data service: Grid.QueryChanged -> Invoke Things.DataService
  • Bind the grid page row size config into the data service parameter: Grid.PageRowSize -> Things.DataService.params.pageSize
  • Bind the grid page row offset into the data service parameter: Grid.PageRowOffset -> Things.DataService.params.offset
  • Bind the grid event that's fired when a new page is requested to invoke the data service: Grid.PageRequested -> Invoke Things.DataService
  • To reset Grid.Query, Grid.PageRowSize, Grid.PageRowOffset (e.g., when the user wants to load a completely different dataset): Button.Clicked -> Invoke Grid.ResetGrid