Widget communication

A widget in ArcGIS Experience Builder is a functional unit: a widget focuses on a single pice of functionality. In many cases, however, we need multiple widgets to work together to complete a task. To do this, we need ways to allow widgets to communication with each other at the framework level. This can be accomplished in Experience Builder in the following ways:

  1. Configurable:
    1. Use the same data source/data view between widgets
    2. Use the same map widget between widgets
    3. Use a widget's output data source
    4. Use message/actions
    5. Use data actions
  2. Programming:
    1. Use widget state to share state between widgets
    2. Provide your own redux store/action/reducer to share state between widgets

Configurable means the user can config the way of communication between widgets in the builder. Programming means the communication between widgets happens in the code.

1.1 Use the same data source/data view between widgets

If multiple widgets use the same data source or data view, they can get the same selection, the same data records, and the same data source status. Widgets can use these data to sync status. For example: multiple widgets can read the same data record but display a different view; one widget can let the user do the selection and another widget can listen to the selection to display the selected data detail.

If multiple widgets use the different data views of the same data source, they still can get the same selection if the selection satisfies the data views filter criteria.

See Use data source in widget

1.2 Use the same map widget between widgets

If multiple widgets use the same map widget, they can get the same JimuMapView instance, which is a wrapper of the ArcGIS Maps SDK for JavaScript MapView instance. After getting the JimuMapView instance, widgets can use addJimuLayerViewCreatedListener() and addJimuLayerViewRemovedListener to listen to the layer view created and removed event to read the changes made by other widgets. For more details, see Use map widget in widget

1.3 Use a widget's output data source

See Widget output data source

1.4 Use message/actions

See Message action for details.

1.5 Use data actions

See Data action for details.

2.1 Use widget state to share state between widgets

A widget, as a React component, can have an internal state. However, other widgets cannot access this state. Jimu uses Redux as its state manager; it saves a lot of info in the Redux store. One piece of the info is called widgetsState; you can find the type definition at jimu-core/lib/types/state. The info stored in widgetsState is accessible by all of the other widgets. To save some info in the widgetsState, please refer to this code snippet:

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
import {appActions} from 'jimu-core';

/*
* Call this when you need to save state.
*
* widgetId: your widget id
* propKey: can be a string with this format "a.b.c"
* value: the info you want to store
*/
this.props.dispatch(appActions.widgetStatePropChange(widgetId, propKey, value))

For example, if you call this.props.dispatch(appActions.widgetStatePropChange("w1", "a.b1", "value1")) and this.props.dispatch(appActions.widgetStatePropChange("w1", "a.b2", "value2")), you'll get this store state in the Redux store:

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
widgetsState: {
    w1: {
        a: {
            b1: 'value1',
            b2: 'value2'
        }
    }
}

To access the data stored by w1 in widget 2, you can select the value from store by using mapExtraStateProps or using useSelect hooks.

widgetsState can only store plain (e.g. does not have functions) JavaScript objects. To store complex (e.g. created from a function constructor or has function members) JavaScript objects, you can use this.props.dispatch(appActions.widgetMutableStatePropChange(widgetId, propKey, value)) to store the value, and use MutableStoreManager.getInstance().getStateValue() to access it.

2.2 Provide your own redux store/action/reducer to share state between widgets

This provides a more flexible way to customize your state management. You can find this is almost the same as the Redux approach. As we know, Redux has only one store and one root reducer, which is used by jimu. To let the widget developer use the normal Redux approach to manage state, jimu defines a ReduxStore extension point; widgets that need to use Redux can provide an extension for this extension point.

  • Create an extension class to implement the ReduxStoreExtension interface; let's call it my-store.ts.
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import {extensionSpec} from 'jimu-core';

export default class MyReduxStoreExtension implements extensionSpec.ReduxStoreExtension{
    getActions(){
        // return your redux actions.
    }

    getInitLocalState(){
        // return your redux init local state.
    }

    getReducer(){
        // return your redux reducer.
    }

    getStoreKey(){
        // return your redux local key.
    }
}
  • Declare the extension in widget manifest.json
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
"extensions": [
    {
      "name": "My Store",
      "point": "REDUX_STORE",
      "uri": "my-store"
    }
]

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.