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:

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 };
    }
}