result-api
This bundle provides an API for displaying results for example from a selection in a central data table component, called result-ui.
The API of this bundle is described in the API documentation.
Configuration Reference
The following code sample shows the configurable properties and their default values:
"result-api": {
"Config": {
"maximal-item-count": 10000,
"item-fetch-chunk-size": 1000,
"replace-opened-tables": false,
"remove-empty-tables": true,
"clear-filter-on-datatable-select": true,
"clear-selection-on-datatable-select": true,
"zoomto-selected-datatable": true,
"zoomto-extent-expansion-factor": 1.1,
"zoomto-point-scale": 10000,
"highlight-symbols": {},
"date-format": "datetime",
"digit-separator": true,
"places": 3,
"excluded-fields": [
"objectid",
"objectid_0",
"objectid_1",
"shape",
"shape_length",
"shape_area",
"st_area(shape)",
"st_length(shape)",
"st_area",
"st_length"
]
}
}
Property | Type | Description |
---|---|---|
maximal-item-count |
Number | Defines the maximal number of fetched and displayed items. |
item-fetch-chunk-size |
Number | Defines the amount of items fetched directly with a single request. |
replace-opened-tables |
Boolean | If true new data tables replace the currently shown. If false the new data tables are combined with the already shown ones. |
remove-empty-tables |
Boolean | If true a data table without any data will be automatically removed. |
clear-filter-on-datatable-select |
Boolean | If true the filter state of a table is cleared when a data table is selected. |
clear-selection-on-datatable-select |
Boolean | If true the selection state of a table is cleared when a data table is selected. |
zoomto-selected-datatable |
Boolean | If true the map will zoom to the contained features when a data table is selected. |
zoomto-extent-expansion-factor |
Number | Defines the expansion value of an extent to zoom to. Default is 1.1 . |
zoomto-point-scale |
Number | Scale used to zoom to point geometries. Default value is 10000 . |
date-format |
String | Formatter property: Format of displayed date values. Available values are listed in Formatting of displayed values. |
digit-separator |
boolean | Formatter property: Indicates if a separator is used in numeric values to mark a thousand. Default value is true . |
places |
Number | Formatter property: Number of digits shown after the decimal separator. Defaults to 3 |
highlight-symbols |
Object | Allows overwriting or customization of the highlight symbols. Consider the Customizing the map highlighting section. |
excluded-fields |
Array of Strings | Defines a case insensitive list of fields that are not displayed. To display all fields, set "excluded-fields": [] . |
Use Cases
Customizing the map highlighting
To customize the geometry rendering of table entries in the map, change the highlight-symbols
property as described in the following.
This sample configuration changes the default color of items to yellow
, selected items to a dark red
outline and focused items to a red
outline:
"result-api": {
"Config": {
"highlight-symbols": {
"default": {
"color": [255, 255, 0, 125],
"outline": {
"color": [255, 255, 0, 255]
}
},
"default-selected": {
"outline": {
"color": [125, 0, 0, 255]
}
},
"default-focused": {
"outline": {
"color": [255, 0, 0, 255]
}
}
}
}
},
To change the highlighting of a specific geometry type, use the type name instead of the default
prefix.
The following sample changes the size of point symbols:
"result-api": {
"Config": {
"highlight-symbols": {
"point": {
"size": 8
},
"multipoint": {
"size": 8
}
}
}
},
The default configuration of the different geometry types is shown in the following:
{
"default": {
"color": [0, 255, 255, 64],
"outline": {
"color": [0, 255, 255, 255],
"width": 2
}
},
"default-selected": {
"color": [0, 255, 0, 64],
"outline": {
"color": [0, 255, 0, 255]
}
},
"default-focused": {
"outline": {
"color": [255, 0, 0, 255]
}
},
"point": {
"type": "esriSMS",
"style": "esriSMSCircle",
"size": 16
},
"point-focused": {},
"point-selected": {},
"multipoint": {
"type": "esriSMS",
"style": "esriSMSCircle",
"size": 16
},
"multipoint-focused": {},
"multipoint-selected": {},
"polyline": {
"type": "esriSLS",
"style": "esriSLSSolid",
"width": 1.3
},
"polyline-focused": {},
"polyline-selected": {
"width": 3
},
"polygon": {
"type": "esriSFS",
"style": "esriSFSSolid"
},
"polygon-focused": {},
"polygon-selected": {}
}
Geometries of type polyline
use the outline.color
of the default-*
templates as color
values.
Showing data inside the result UI
To trigger the display of data, inject the result-api.ResultViewerService
in your bundle:
"components": [
{
"name": "MyComponent",
"references": [{
"name": "resultViewerService",
"providing": "result-api.ResultViewerService"
}]
}
]
To show the data use the service's open()
method:
const tableCollection = ... // see below how to create a data table collection
this.resultViewerService.open(tableCollection);
Data from a store
The open
method of the result-api.ResultViewerService
expects a DataTableCollection
as an input parameter.
A DataTableCollection
can be created from a store using the dataTableFactory
property of the result-api.ResultViewerService
as shown below:
// The store needs to provide the Store interface of the store-api.
// This store is used as data source
const store = ...
// only the items with the ids returned by the idsProvider
// are fetched from the store and shown in the UI
const idsProvider: DatasetItemIdsProvider = async ({limit}) => {
// the limit option is the maximal amount of items which will be fetched
// the id provider may ignore the information or use it to reduce the fetched results
const result = await store.query({}, {
count: limit
});
return {
ids: result.map((item) => item.id)
};
};
// dataTableFactory is used to create a DataTableCollection from the store
const dataTableFactory = this.resultViewerService.dataTableFactory;
const dataTable = await dataTableFactory.createDataTableFromStore(
dataTableTitle: "MyTopic",
dataSource: store,
idsProvider
);
const dataTableCollection = dataTableFactory.createDataTableCollection([dataTable]);
this.resultViewerService.open(dataTableCollection);
Analogous to this, results can be opened from a store and a complex query:
const store = ...
const queryExpression = ... // a Complex Query expression (see store-api bundle)
const queryOptions = ... // additional query options, e.g. the { fields: { [name]: boolean } } option can be used to reduce the shown columns
const dataTableFactory = this.resultViewerService.dataTableFactory;
const dataTable = await dataTableFactory.createDataTableFromStoreAndQuery(
dataTableTitle: "MyTopic",
dataSource: store,
queryExpression,
queryOptions
);
const dataTableCollection = dataTableFactory.createDataTableCollection([dataTable]);
this.resultViewerService.open(dataTableCollection);
NOTE
A data table fetches the data from the stores using the complex query $in
operation, for example { id : { $in: [1,2,3] }}
.
The $in
operation must be supported by stores to be displayed successfully.
Results from a spatial selection
This bundle provides a default integration to the selection bundle. Incoming selection results will be automatically shown, if one is available.
Formatting of displayed values
It is possible to control, how numeric and date values are displayed in cells of a data table. For this, the following properties may be used:
"result-api": {
"Config": {
"date-format": "datetime",
"digit-separator": true,
"places": 3
}
For date-format
, the following values are possible:
Format | Example |
---|---|
date |
Oct 19, 2022 |
time |
4:33 PM |
datetime |
Oct 19, 2022, 4:33 PM |
short-date |
12/31/1969 |
short-date-short-time |
12/31/1969, 7:00 PM |
short-date-short-time-24 |
12/31/1969, 19:00 |
short-date-long-time |
12/31/1969, 7:00:00 PM |
short-date-long-time-24 |
12/31/1969, 19:00:00 |
long-month-day-year |
December 31, 1969 |
long-month-day-year-short-time |
December 31, 1969 at 7:00 PM |
long-month-day-year-short-time-24 |
December 31, 1969 at 19:00 |
long-month-day-year-long-time |
December 31, 1969 at 7:00:00 PM |
long-month-day-year-long-time-24 |
December 31, 1969 at 19:00:00 |
day-short-month-year |
Dec 31, 1969 |
day-short-month-year-short-time |
Dec 31, 1969, 7:00 PM |
day-short-month-year-short-time-24 |
Dec 31, 1969, 19:00 |
day-short-month-year-long-time |
Dec 31, 1969, 7:00:00 PM |
day-short-month-year-long-time-24 |
Dec 31, 1969, 19:00:00 |
long-date |
Wednesday, December 31, 1969 |
long-date-short-time |
Wednesday, December 31, 1969 at 7:00 PM |
long-date-short-time-24 |
Wednesday, December 31, 1969 at 19:00 |
long-date-long-time |
Wednesday, December 31, 1969 at 7:00:00 PM |
long-date-long-time-24 |
Wednesday, December 31, 1969 at 19:00:00 |
long-month-year |
December 1969 |
short-month-year |
Dec 1969 |
year |
1969 |
The global values defined in this bundle may be overridden per store or layer, that is used as a data source. See agssearch or map-init for details.
Adding custom table actions
Users can execute table actions on a (sub)set of items, such as creating an export. There are two types of table actions:
- Bulk actions are performed on a set of selected rows
- Row actions are performed on a single row independent of the selection state
Adding a custom bulk action
To provide a bulk action that operates on multiple items, implement the BulkButtonTableAction
interface:
import type { BulkButtonTableAction, BulkActionContext } from "result-api/api";
export class MyBulkAction implements BulkButtonTableAction {
id = "my-bulk-action-01";
uiType = "button" as const;
label = "My Bulk Action";
tooltip = "Triggers MyBulkAction";
icon = "icon-play";
// priority: optional property for controlling the of table actions referenced by '*'
priority = 1;
async trigger(actionContext: BulkActionContext): Promise<void> {
const dataTable = actionContext.dataTable;
const tableModel = dataTable.tableModel;
const selectedIds = tableModel.getSelectedIds();
...
}
}
To register an action provide the result-api.BulkTableAction
interface:
{
"name": "MyBulkAction",
"provides": ["result-api.BulkTableAction"]
}
A BulkButtonTableAction
has to provide a trigger()
method that consumes a BulkActionContext
. With this context the data
is passed to the action, which can use it at execution time. For example, an action can query the set of items currently selected in the UI.
Adding a custom row action
To provide an action that operates on a single item, implement the RowButtonTableAction
interface.
import type { RowButtonTableAction, RowActionContext } from "result-api/api";
export class MyRowAction implements RowButtonTableAction {
id = "my-row-action-01";
uiType = "button" as const;
label = "My Row Action";
tooltip = "Triggers MyRowAction";
icon = "icon-play";
// priority: optional property for controlling the order of table actions referenced by '*'
priority = 1;
async trigger(actionContext: RowActionContext): Promise<void> {
const rowItem = actionContext.rowItem;
...
}
}
To register a row action provide the result-api.RowTableAction
interface:
{
"name": "MyRowAction",
"provides": ["result-api.RowTableAction"]
}
A RowButtonTableAction
has to provide a trigger()
method that consumes a RowActionContext
. With this context the data
is passed to the action, which can use it at execution time. For example, an action can query the item on which the action was triggered.
Order of table actions
The order of actions can explicit be defined in the result-ui.
There is a placeholder *
available which allows to insert actions dynamically.
The order of actions references by this placeholder are defined by the attributes of priority
, label
and id
of the actions.
As higher the priority of an action as early the action is sorted into the list of actions.
Actions with the same priority are ordered alphabetically according to their label
.
Actions with the same priority and same label are ordered alphabetically according to their unique id
.
The default priority
of an action is 0
.
The priority can only be set by developers and it is up to a developer to decide if it can be overwritten by configuration.
Controlling the display state of actions by rules
It is possible to make actions enabled, disabled, visible, or invisible in the UI dependent on different states of the displayed data. There are several means to control the display state of an action:
1. Use tool rules:
Actions can be displayed depending on tool rules. For example, to enable an action button in the UI only,
if at least one item is selected, add the following "rules"
item:
{
"name": "MyBulkAction",
"provides": ["result-api.BulkTableAction"],
"propertiesConstructor": true,
"properties": {
"rules": [{ "result-ui-min-selected-items": 1 }]
}
}
Commonly used rules are:
{
"rules": [
{ "result-ui-min-selected-items": 1 }, // minimal number of selected items in table
{ "result-ui-selected-table": "myStore" }, // specific table
{ "minScale": 10000, "maxScale": 10000 }, // current scale of map
{ "roles": ["maAdmin", "maEditor"] } // user roles
]
}
2. Programmatically decide when to display an action
An action can implement the optional function provideDisplayState()
to declare its own display state:
export class MyRowAction implements RowButtonTableAction {
provideDisplayState(dataTable: DataTable, rowItem: DatasetItem): Partial<TableActionDisplayState> {
return {
visible: true,
enabled: false
};
}
}
3. Programmatically decide when to display an action in a component
Provide a result-api.TableActionDisplayStateProvider
component to decide, which actions may be displayed:
export class MyDisplayStateProvider implements TableActionDisplayStateProvider {
provideDisplayState((
actionId: string,
dataTable: DataTable,
rowItem?: DatasetItem
): Partial<TableActionDisplayState> | undefined {
if (actionId === "MyAction") {
return { enabled: true };
}
// only display for specific topic
if (dataTable.dataset.id=== "countries") {
return { enabled: true };
}
return { visible: false };
}
}