Experience Builder can be extended through building custom widgets, creating custom themes, custom data sources, and message/actions. All of this is possible
by using Experience Builder's extensibility framework called
jimu, which is built on the following components:
- React + Redux framework
- Bootstrap 4 for user interface
TypeScript is required to develop widgets, themes, etc. in Experience Builder. It provides many advantages such as:
- Instant type error detection
- Better IDE Experience
- Self-documenting code
- More readable and easier to understand
Data source defines how your widget accesses data. For example, when data is from a remote server, the widget can use a data source class to query the data to the client side. When data is generated by a widget, it can be used by another widget by putting itself into a data source class.
At a high level, a data source has a schema, some records, and may have some child/parent data source. In addition, every data source has a type, id, and status
to help identify it. The
DataSource interface is defined in the
jimu-core package; it defines some of the following methods and properties:
id: the data source id.
type: property used in the widget to check which type of data source it is using.
fetchSchema: every data source must implement this method to return the schema. This is the schema defined in the remote data service. For example, when a user adds a data source in Experience Builder, the data source schema is not saved in the app config; instead, the
fetchSchemamethod is called to get the latest data source schema.
getSchema: method used by the widget to access the data source schema and fields in the data source.
getRecords: method used by the widget to access the data records in the data source.
getStatus: the widget will use this property to get the status of the data source. Some of these statuses include
A data source can have sub data sources. As a result, you may include more than one data source to make it easier to use. This kind of data source is called a
WebMapDataSource is a
DataSourceSet is also a type of data source once the
isDataSourceSet property is set to true.
Data source is managed by the
DataSourceManager to create and get data sources.
When multiple widgets connect to a single data source, a widget may want to see a local view of the data source. In this scenario, you would use a data view. The relationship between a data view and data source is very similar to the relationship between a view and a table in a relational database. Although a data source in Experience Builder is a view of the actual remote data source on the client-side, you can think of a data source as a table and data view as a view.
An app creator can create a data view from a data source and connect a widget to the data view in the builder. At the API level, the data view is managed by using the
DataSource class, so the data view has the same interface and behavior with the data source just with some attribute differences.
To simplify the use of a data source, a
DataSourceComponent component is defined. This accepts the
useDataSource property and returns the data source object and its status info through a callback.
It also accepts a function as its child, which can be used to get the data source object and info to render the data in the data source. The
DataSourceComponent component can also accept an optional
query property and will reload the data when the query is changed.
To support the most commonly used data formats such as a feature service, the API has a
QueriableDataSource interface and an abstract class
This interface has properties including
query etc. The difference between the
query methods is such that
load updates the
records property and the status of the data source, while
query queries and returns the records only.
More specifically, we define the
FeatureLayerDataSource data sources in Experience Builder to access a feature layer. If the data source is created from a standalone feature layer, the object does not have
layer property; If it's created from a feature layer contained in a webmap/webscene, the object will have the
layer property, which is a
In general, a data source is saved in two places: the data source object is saved and managed in
DataSourceManager, and the data source info is saved in a redux app store.
DataSourceComponent, the component will call
DataSourceManager to create the data source on demand, and return the data source object and
dataSourceInfo by using a callback prop.
dataSourceInfo, the data source's
selectedIds, etc. can be returned.
Most of the ArcGIS server services are mapped to data source for easy access, such as
WebSceneDataSource in the
The data source provided by
RepeatedDataSourceProvider is called a repeated data source. All children widgets of the widget that provide a data source will receive the repeated data source.
This is similar to React's Context. A widget can access repeated data source by
this.props.repeatedDataSource. The repeated data source will get the data source's
Any widget can provide repeated data source by using
List widget in Experience Builder is a good example that provides a repeated data source.
To use a repeated data source, add the
supportRepeat property in a widget's manifest file.
jimu-corepackage loads and parses the app config, then loads the layout, theme, and widgets based on the app config. To support this, this package defines several classes like WidgetManager, ConfigManager, ThemeManager, etc. Also, the jimu-core defines the interface of the widget, some common types, and some extension points, which are subject to be extended by other packages and widgets.
jimu-layoutspackage contains common implementations for layout widgets.
jimu-uipackage contains all the UI components that experiences will utilize. Under the hood, it uses reactstrap and emotion-js. Additionally, more components that are not in reactstrap are added. To reduce the loading size, the components are split into some entries, such as index, setting-components, sql-expression-builder, etc. See API for details.
jimu-for-builderpackage supports developing the widget setting page.
JimuMapView to ensure a consistent extensibility model when creating widgets, message/actions, etc.
To create a
JimuMapView object, a widget can use the
JimuMapViewManager.createJimuMapView() method. A
JimuMapView object has these main properties:
view: the map/scene view object.
datasourceId: the data source (webmap/webscene) that creates the view
mapWidgetId: the widget that creates the object
jimuLayerViews: the layer view object wrapper
The widget that needs to use the map/scene view can use the
JimuMapViewSelector component in the setting page to select a map/scene view. This will also use
JimuMapViewComponent to access the
Message/action is a way to support communication between widget to widget, widget to framework, and framework to widget. Widget/framework can publish a message, and they can listen to a message as well.
A message is identified by
MessageType, which is defined by the jimu framework. There are some message types defined in jimu, such as
DataRecordsSelectionChange. There will be more message types in future releases.
Learn more about how to create a message/action.
The page in an experience is not a physical HTML web page; it is a conceptual page, however, it behaves like an actual HTML web page. It is implemented by using a
div HTML tag.
An experience must have at least one page, and it can have multiple pages. There are two types of page layouts in Experience Builder: a full screen app page and a linear scrolling page; the former one looks like an application and the latter one looks like a web page.
The page contents (widget/section) are organized by layout rules, such as a fixed layout and flow layout. To make the page responsive on different screen sizes, Experience Builder supports the configuration of layouts by size modes. These are defined by
The configuration of each layout is an adaptation of the experience, which offers greater flexibility with more customization of the application and better usage
of the screen size. A good illustration of this design is the City Explorer template. When the application is viewed on a large and medium screen,
the map is visible and is included in the configuration; however, when it is viewed on a mobile device, the map widget is removed from the first page and is only displayed on the second page after a user selects a feature in the list widget.
A screen group is a layout container with multiple screens to organize content and widgets on scrolling pages. Each screen has a main stage and can also have a scrolling panel, depending on the screen group template. When scrolling to a screen group, it occupies the entire screen height. If a screen group has scrolling panels, as end users scroll through the content in a panel, the main stage remains in place, switching only as the last panel scrolls away. If a screen group has no panels, the main stage remains in place until it scrolls one full screen height.
Theme defines an experience's looking and feel. Experience includes out-of-the box(OOB) themes, and custom themes can be created. Learn more about theme development.
A widget is a configurable functional unit. It is the building block used to create pages for an experience. Experience Builder provides OOB widgets, such as map, button, list, etc., and custom widgets can be created. A widget usually provides a setting UI to allow users to configure its functionality in the builder environment. If a widget has configurable options but does not include a setting UI, a JSON editor can be used to configure it.
Learn more about widget implementation.
The window is similiar to a page, you can add any widget to it and it has two configurations for displaying content: fixed and anchored. The fixed window creates a modal that disables the main window but keeps it visible so users can interact with the window before they can return to the experience. A fixed window can be used as a splash screen, opened with a page or from a widget. An anchored window is triggered from a widget such as a button or a text widget.