Table
This widget shows a tabular view of data.
Table Data
Refer to the generic widget page for a description of the general principles governing the treatment of data retrieved from a dataSource
Data from Table Holder / KPI Table
The widget fetches the table data from the system and does auto discovering of the header columns. This property is an objspec.
{
"dataSource": {
"type": "read",
"path": "/System/Core/Examples/WebStudio/Tables/SalesOrders"
}
}
Options
The options section is used to control various aspects of the appearance and behavior of the table.
{
"options": {
"allowSorting": false,
"alternateColumnColoring": true,
"alternateRowColoring": true,
"editable": false,
"multi": true,
"multiMax": 3,
"multiMin": 1,
"pageSize": 20,
"pagination": true,
"showHoverHighLight": true,
"showRefreshButton": true,
"showSelectedRow": false,
"showToolbar": true,
"showRowNumbers": true,
"style": {
"backgroundColor": "Gainsboro",
"color": "blue",
"fontFamily": "\"Courier New\", Courier, sans-serif",
"fontWeight": "bold",
"fontSize": "20px",
"textAlign": "left",
"whiteSpace": "pre-line"
},
"header": {
"style": {
"backgroundColor": "DimGrey",
"color": "white",
"fontWeight": "bold"
}
},
"refreshInterval": 30
}
}
name | description |
---|---|
|
When editable is set to true the cell values can be modified. Note that this only affects the original dataset if the table is saved and the user has the permissions to overwrite data. |
|
Can disable sorting icons and sorting functionality. |
|
Apply alternating light and dark column backgrounds. |
|
Apply alternating light and dark row backgrounds. Can be used together with |
|
Used to define |
|
Allow selection of multiple rows. When |
|
Minimal needed selected rows before the table onSubmit action can be triggered. |
|
Maximum allowed selected rows. |
|
When set to |
|
With |
|
Array of conditional formatting rules. See below |
|
Enable/disable hover effect on the table rows. |
|
Background color will change when a table row is clicked. Defaults to true when |
|
Set this to |
|
When set to |
|
Use to hide the complete toolbar. |
|
Property used to define static style settings for the table header and body. See Table styles for more details. |
|
Property used to define static style settings for the table based on the active theme. For example:
|
|
Refresh with an interval in seconds. |
Table Styles
There are a number of properties available in the model which allow the table header and content to be styled. The order of precedence in which styles are applied depends on where they are declared, as shown here from lowest to highest:
-
options
: For all widgets, overall style settings can be defined in theoptions
property, as shown above. -
options.rules
: Conditional stylingrules
declared in theoptions
property provide a means to control the appearance of matching rows. Rules don’t affect the header appearance. -
schema
: Column specific styles can be defined in theschema
section of the model. These affect both the table header and data. -
options.header
: Used to explicitly control the appearance of the header row. When set it takes precedence over the style settings in both theoptions.style
andschema.style
sections. -
schema
specificheader
: The appearance of a column header can be further customized on a column by column basis using theheader
element in theschema
section. -
schema
specificrules
: Conditional styling defined in theschema
section affects only the data cells for which therule
conditions match, as opposed to those in theoptions
, which affect the row as a whole.
For each of the properties listed style
and/or styleByTheme
can be defined. styleByTheme
settings override style
settings at the same level.
Conditional Styling Using Rules
The appearance of individual data rows and/or cells can be configured using rules
. Styling, which needs to be applied conditionally at row level, is configured by rules
inside the options
property, while column/cell specific settings are applied within the schema
elements.
The rules
property is an array, allowing multiple rules
to be applied to the same or different fields.
Each rule entry refers to a field in the data, either explicitly by specifying a name
value, or implicitly by virtue of the schema element the rule resides in. When the field value matches the rule value
, type
or range
the style
/styleByTheme
settings are applied.
{
"options": {
"rules": [
{
"name": "temperature",
"value": 20,
"style": {
"backgroundColor": "green",
"fontSize": "15px",
"fontWeight": "normal"
}
},
{
"name": "temperature",
"range": {
"from": 22,
"to": 26
},
"style": {
"fontWeight": "bold"
}
}
]
}
}
name | description |
---|---|
|
Name of the data field the rule applies to. For rules in the model |
|
Used to define a numeric |
|
Define the appearance of the row or cell when the rule condition is met. |
|
Can be set to either "isNull" or "isUndefined" to match null or undefined fields in the data. This
property takes precedence over |
|
The exact value to match the data field to. |
Schema
The schema defined in the model takes precedence over any returned from the data source.
A schema consist of:
name | description |
---|---|
|
Instead of making every cell editable with setting |
|
The |
|
Used to define which input control is shown when the table filter is activated. Options are:
|
|
When type is |
|
Used to define |
|
Property controlling column visibility (optional) |
|
When column names are repeated in the schema section, WebStudio will automatically generated a unique |
|
This option can be used for hierarchical data structures, it enables collapsing
and expanding table rows. Set |
|
Cell value can be selected from a dropdown list containing predefined values. |
|
Key name of the data field displayed in this column. The name is also used by default to uniquely identify columns in the table. If the same named data field needs to appear in the table multiple times an |
|
When type is |
|
Custom styling rules. |
|
Property to define default sorting on the column. Accepted values: |
|
Optional styling for the column |
|
Optional theme specific styling for the column |
|
Column title. |
|
Tooltip text to display when the mouse hovers over the table column header. If the tooltip is not explicitly set, the column title will be shown instead, or the name if that too is missing. This is useful when explicitly assigning the column width, typically to a number large enough to show the field values, but too narrow to accommodate the title, which might be longer than is needed for the values. |
|
The
|
|
Width can be defined for the columns manually by providing pixel values as string e.g. "300px". |
{
"schema": [
{
"name": "id",
"hidden": true
},
{
"title": "Population",
"name": "population",
"filter": "select",
"type": "number",
"editable": true
},
{
"title": "Value",
"name": "value",
"filter": "slider",
"type": "number",
"numberOfDecimals": 2,
"sort": "desc"
},
{
"title": "Fixed column",
"value": "Click here",
"actions": {
"onClick": {
"type": "notify",
"text": "Fixed column cell clicked!"
}
}
}
]
}
Multiple schema items with the same name
To illustrate the use of repeated names in the schema, consider an example where the data rows include a "timestamp" field expressed as an epoch integer and we want to show the raw number as well as a formatted version.
The data could be something like:
{
"data": [
{
"event": "machine start",
"timestamp": 1635408094000
},
{
"event": "machine stop",
"timestamp": 1635416051000
}
]
}
In the schema the timestamp appears twice. First formatted as a number and then as a date:
{
"schema": [
{
"name": "event",
"title": "Event Description"
},
{
"name": "timestamp",
"type": "number",
"title": "raw timestamp"
},
{
"name": "timestamp",
"type": "date",
"title": "Date-Time",
"format": "YYYY-MM-DD HH:mm:ss"
}
]
}
Note: Looking at the work-model for this table, we see that an
id
= "timestamp_2" was automatically generated in the schema for the second occurrence of the column. It can also be explicitly added to the initial model, in which case we are free to choose theid
value:
{
"schema": [
{ "name": "event", /* etc ... */ },
{ "name": "timestamp", /* etc ... */ },
{
"name": "timestamp",
"id" : "formatted_timestamp",
"type": "date",
"title": "Date-Time",
"format": "YYYY-MM-DD HH:mm:ss"
}
]
}
Dealing with composite data
In most cases the data presented to the table is likely to be in the form of a flat array where each element contains a set of named fields and their values. Something like:
{
"data": [
{
"value": 26,
"location": "Eindhoven"
},
{
"value": 18,
"location": "Cologne"
}
]
}
Mapping these to columns in the table is simply a matter of setting the name
field in the schema
definitions to the corresponding field in the data… like so:
"schema": [
{
"name": "location",
"title": "City",
},
{
"name": "value",
"title": "Temperature"
}
],
Occasionally, you may need to deal with data that has composite values as shown:
{
"data": [
{
"temperature": {
"wetBulb": 22,
"dryBulb": 26
},
"location": "Eindhoven"
},
{
"temperature": {
"wetBulb": 17,
"dryBulb": 18
},
"location": "Cologne"
}
]
}
One way to deal with this would be to transform the data by moving all the fields to the root object. Fortunately this is not necessary since you can bind to nested fields directly. Simply assign the dot-notation property key to the name
parameter in the schema
.
"schema": [
{
"name": "location",
"title": "City"
},
{
"name": "temperature.wetBulb",
"title": "Wet Bulb Temperature"
},
{
"name": "temperature.dryBulb",
"title": "Dry Bulb Temperature"
}
],
Grouped columns
{
"schema": [
{
"title": "Employee",
"columns": [
{
"title": "Name",
"name": "firstName"
},
{
"title": "Last Name",
"name": "lastName"
},
{
"title": "Age",
"name": "age",
"filter": "slider"
}
]
},
{
"title": "Address",
"columns": [
{
"title": "Street",
"name": "street",
"filter": "text"
},
{
"title": "City",
"name": "city"
},
{
"title": "Country",
"name": "country",
"filter": "select"
}
]
}
]
}
Dropdown selection
Select a predefined input value from a dropdown. Inputs need to be defined in the items
array. This can be an array of strings or objects containing a label
and value
. The latter can be used when the text to show should be different from the value
.
Example items
as string array:
{
"schema": [
{
"name": "day",
"title": "Day of week",
"items": [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Saturday",
"Sunday"
]
}
]
}
Example items
by defining labels and values:
{
"schema": [
{
"name": "day",
"title": "Day of week",
"items": [
{
"label": "MON",
"value": "Monday"
},
{
"label": "TUE",
"value": "Tuesday"
}
]
}
]
}
Formatting
{
"schema": [
{
"name": "temperature",
"title": "Temperature",
"type": "number",
"numberOfDecimals": 2,
"engUnit": "°C"
},
{
"name": "timestamp",
"title": "Timestamp",
"type": "date",
"format": "YYYY-MM-DD HH:mm:ss.SSS"
},
{
"name": "status",
"title": "Status",
"enumMode": "valueToName", // valueToName (default), nameToValue
"enum": {
"Dry": 1,
"Wet": 2
}
}
]
}
Enum formatting can do valueToName
(default) or nameToValue
.
-
valueToName
: Table cell value will be matched with a value of an enum and the name will be shown in the table cell. -
nameToValue
: Table cell value will be matched with a name of an enum and the value will be shown in the table cell.
Style
Cell or column based styling can be defined in the style
within a schema
element.
{
"schema": [
{
"name": "value",
"title": "Value",
"style": {
"backgroundColor": "#00c302",
"fontSize": "15px",
"fontWeight": "bold",
"whiteSpace": "pre-line"
}
}
]
}
Conditional styling on schema level applies for to cell. The name
field is optional and can be defined in case the
value match needs to be done with another data field. The styles of all matching rules will be applied to the cell.
Cell based rules:
{
"schema": [
{
"name": "value",
"title": "Value",
"style": {
"backgroundColor": "#00c302",
"fontSize": "15px",
"fontWeight": "bold",
"whiteSpace": "pre-line"
},
"rules": [
{
"value": 1,
"style": {
"backgroundColor": "green",
"fontSize": "15px",
"fontWeight": "normal"
}
},
{
"value": 2,
"style": {
"color": "yellow"
}
},
{
"range": {
"from": 5,
"to": 10
},
"style": {
"color": "yellow"
}
}
]
}
]
}
Hierarchical Data
Data field has a key children
, which is used in schema with isExpander
to create hierarchical table layout.
"data": [
{
"Item": "Pencil",
"Total": 189.05,
"Unit Cost": 1.99,
"children": [
{
"Item": "Pencil",
"Total": 59.7,
"Unit Cost": 1.99,
"OrderDate": "2019-06-08"
},
{
"Item": "Pencil",
"Total": 59.7,
"Unit Cost": 1.99,
"OrderDate": "2019-06-10"
}
]
}
]
"schema": [
{
"name": "children",
"collapsedIcon": "▷",
"expandedIcon": "▽",
"isExpander": true
},
{
"name": "Item",
"title": "Item"
},
{
"name": "Total",
"title": "Total"
},
{
"name": "Unit Cost",
"title": "Unit Cost"
},
{
"name": "OrderDate",
"title": "Order date",
"type": "date",
"format": "YYYY-MM-DD"
}
],
Toolbars
Define custom tools to be added to the toolbar and their actions.
{
"toolbars": {
"top": {
"tools": {
"addRow" : {
"type" : "button",
"title": "",
"icon": {},
"style": {},
"styleByTheme": {},
"actions": {
"onClick": {}
}
}
},
"toolsOrder": {
"leftOrTop": ["addRow"]
}
}
},
}
Field | Description | |||
---|---|---|---|---|
|
Currently toolbars can only be located at the top of the widget. Other options may be added later. |
|||
|
Define the order in which the tools are drawn. For now, they are always arranged from left to right. Additional options, to have center or right aligned tools, may be added later. |
|||
|
List of tool-names indicating the order they are drawn from left to right. The property is called |
|||
|
Contains the "named" tools to be added to the toolbar. In the example above, a single addRow button is defined. The name is used to set the display order in the |
|||
|
Define the appearance and actions for a tool. The name should be chosen to reflect its purpose. |
|||
|
The only tool type supported at the moment is button. While it is the only option, the property can be omitted. |
|||
|
Optional tool text. Can be omitted if only an Icon should be displayed. |
|||
|
Tool icon. Can be omitted if only the title is needed. |
|||
|
Optional styling to be applied. |
|||
|
Optional theme specific styling |
|||
|
Define tool actions to respond to. Currently the only action trigger available is
|
State
The table widget maintains some dynamic state information in the state
property to record the currently selected
row(s) as well as the active search and filter options.
{
"state": {
"selectedRowIndex": [],
"filters": [
{
"name": "Count",
"value": [
2,
5
]
}
],
"search": {
"value": ""
}
}
}
Field | Description | |
---|---|---|
|
list of 0 based row indices of selected rows |
|
|
List of filter objects |
|
|
Name of the column the filter is applied to |
|
|
Filter value. The content of this field depends on the type of the filter. |
|
|
Mode selected for the
|
|
|
Used in place of |
|
|
Search text |
These may be set in the initial model, but it is more common to access and manipulate the values at run-time.
Note: If the filter
type is set to "none" in the schema
for a particular column, the filter state is ignored for that column.
Note: The state properties can be modified using action pipelines to explicitly set the filters, selected rows or search values. When applying such changes the current state fields need to be overwritten in their entirety. Changing fields inside the root level properties is not supported.
To put this into perspective, consider the following example: Suppose we want to change the "range" filter on the "Count" field so it ends at 10 rather than 5, as in the example above.
We might be tempted to do something like this:
{
"type": "modify",
"id": "table",
"set": [
{ // This is not supported !
"name": "model.table.state.filters.0.value.1",
"value": 10
}
]
}
What we need to do instead, is to provide the complete filter array
{
"type": "modify",
"id": "table",
"set": [
{
// The model field being modified is the "filter" array
"name": "model.table.state.filters",
// The value assigned to it must includes all filter settings to be applied.
"value": [
{
"value": [
3,
10
],
"name": "Count"
}
]
}
]
}
In this case only one field is involved in the filter, but if there were more, they would all need to be included in the
filters
array even if only one of them changes.
Actions
-
onClick
: Cell is clicked. Can be defined via the Schema. -
onSelect
: Single row is selected. -
onSelectionChanged
: Perform an action each time the selection is changed. -
onSubmit
: Submit button is clicked and selected rows are in the message payload.
onClick
An onClick
action defined in the schema
is used to trigger pipeline execution when any field in the relevant column is clicked.
{
"schema": [
{
"name": "value",
"title": "Value",
"actions": {
"onClick": [] // Can be a single action or action pipeline.
}
}
]
}
The input message payload
will contain the complete row data and the selected cell info. Example:
{
"row": {
"_idx": 1,
"name": "Temperature",
"value": 26
},
"cell": {
"_idx": 2,
"name": "value",
"value": 26
}
}
Example to delete a row from the table using onClick
The schema definition below shows how to add a column to your table containing an icon, which can be clicked to delete a row.
{
"schema": [
{
"type": "string",
"value": "🗑",
"actions": {
"onClick": [
{
"type": "transform",
"aggregateOne": [
{
"$project": {
"removeFromArray": [
{
"name": "model.data",
"idx": {
"$subtract": [
"$row._idx",
1
]
}
}
]
}
}
]
},
{
"type": "modify",
"refresh": false,
"id": "self"
}
]
}
}
]
}
In the pipeline, the delete is preformed in two steps.
-
From the incoming message,
row._idx
is used to initialize theremoveFromArray
parameter needed by themodify
action. Since therow._idx
is provided as a 1-based number, we need to subtract 1 before assigning it. The output message from the first step after clicking on the icon in the first table row looks like this:{ "payload": { "removeFromArray": [ { "name": "model.data", "idx": 0 } ] } }
-
modify
is invoked on the table, without specifying theremoveFromArray
property which will be taken from the incoming message. Therefresh
: false setting prevents the data from being reloaded from the back end when the table uses adataSource
onSelect
Gets invoked when a row is selected. The input message payload
contains the selected row data.
{
"actions": {
"onSelect": [
{
"type": "function",
"lib": "library-name",
"func": "function-name",
"farg": {} // This will be set automatically.
}
]
}
}
Transforming the selected row data and invoke a function:
{
"actions": {
"onSelect": [
{
"type": "transform",
"aggregateOne": [] // This will return one object instead of an array.
},
{
"type": "function",
"lib": "library-name",
"func": "function-name",
"farg": {} // This will be set automatically.
}
]
}
}
Send a message to another widget with selected row data:
{
"actions": {
"onSelect": [
{
"type": "send",
"to": "widget01"
}
]
}
}
onSelectionChanged
Gets invoked when a row is (de)selected. The input message payload
contains all the selected rows (array).
{
"actions": {
"onSelectionChanged": [] // Can be a single action or action pipeline.
}
}
onSubmit
The selected rows (array) are set on the input message payload
. Whether rows can be selected with respect to the
minimum and maximum number of selected rows, can be set with multi
, multiMin
and multiMax
in the
Options.
{
"actions": {
"onSubmit": []
}
}
Receive messages (Send Topics)
This widget receives messages from others. Besides the generic, this widget also support topics:
-
selectRows
: Can be used to select one or more rows in the table. The messagepayload
should contain arowIndex
array, which contains the index(es) of the rows which need to be selected.
Here’s an example to send a message to a table widget with an array of the selected rows:
{
"type": "send",
"to": "table",
"message": {
"topic": "selectRows",
"payload": {
"rowIndex": [
5,
6
]
}
}
}
Collect
Collect without a topic
defined will result in the data rows.
This widget supports the following topics to collect data:
-
No topic defined: collects all the data rows.
-
selectedRows
: collects the selected rows data.
Here’s an example of getting the selected rows data from a table widget by using an onClick action of a text Widget:
{
"type": "text",
"text": "Click here",
"actions": {
"onClick": [
{
"type": "collect",
"from": "table",
"message": {
"topic": "selectedRows"
}
},
{
"type": "consoleLog",
"tag": "Selected Row Data"
}
]
}
}