Overview

ArcGIS WebApp Builder is built with ArcGIS API for JavaScript and Dojo. It allows you to customize and extend functionalities by creating your own widgets and themes.

Understanding widgets, panels and themes

Widget

An ArcGIS WebApp Builder widget is a set of text files that you can share, move, and deploy to an ArcGIS WebApp Builder application.

Widget structure

A widget can be a single JavaScript file, which is an AMD module, or can be as complicated as an AMD package, such as a Dojo package. The above screen capture represents a widget that has a template, configuration file, style file, and internationalization support.

Typically, a widget encapsulates a set of isolated and focused business logics in which users can conduct a task. A widget is not only visually interactive with the user, but can also connect to server side resources such as map services from ArcGIS Server or ArcGIS Online.

An ArcGIS WebApp Builder widget must extend the BaseWidget class (BaseWidget.js). By extending the BaseWidget class, a new JavaScript class is recognized by the ArcGIS WebApp Builder’s WidgetManager as a deployable widget.

For more details, see the walkthrough for developing a widget.

Panel

A panel is a UI element that displays the widget’s content. Multiple widgets can display in one panel.

By using panel, the widget developer does not have to deal with how the widget and its content (data) displays in the HTML viewer. However, the widget developer can choose to not utilize the provided panel (for more details, see the Widget Development section). For example, the Scalebar widget has its own unique UI.

You can modify or create new panels to obtain new functionality, such as making the widget display movable by dragging, and so on.

Theme

A theme defines the UI of the web app created by ArcGIS WebApp Builder. Themes define:

  • How the widget displays via theme panels
  • The color scheme, fonts, and so on via styles
  • Where widgets are located on the viewer’s UI, via one or more configuration files

Skill and software needed for ArcGIS WebApp Builder developers

Developers need sufficient knowledge and experience using HTML and JavaScript to develop web applications.

Dojo is the base platform for [ArcGIS API for JavaScript] (https://developers.arcgis.com/en/javascript/) and ArcGIS WebApp Builder.

To develop a widget for ArcGIS WebApp Builder, a level of familiarity with the ArcGIS JavaScript API is recommended, or at least familiarity with the samples provided by Esri.

Although the required software is a basic text editor, a standards-compliant web browser, and an Internet connection, the following are recommended for efficient development:

  • Sublime or Aptana Studio IDE
  • Chrome (latest version)
  • Firefox (latest version) with the Firebug plug-in

Resources

Widget development

To develop a widget, create a new BaseWidget subclass in the widget folder. The following demonstrates how to create a custom widget from scratch. The screen captures shown below are from Sublime text in which the ArcGIS WebApp Builder directory opens.

All of the code for demo widgets are in the stemapp/widgets/samplewidgets/Demo folder. You can view demo widgets through http://your host/webapp/?config=sample-configs/config-demo.json.

Widget naming convention

Although a widget’s resources can be named differently, the following are recommended:

  • Widget class- Uses the convention name, Widget.js.
  • Widget template (widget UI)- Use the same name as the widget class except with a .html extension. For example, Widget.html.
  • Widget Configuration File- Use the config.json file and put it into the widget folder.
  • Widget I18N File (locale file)- Use the strings.js file and put it into the nls folder. For more information, see Dojo’s documentation at http://dojotoolkit.org/documentation/tutorials/1.8/i18n/.
  • Widget style file- Use the style.css file and put it into the css folder. Put all of the images used by the style into the css subfolder, called images.
  • Widget icon files- Use the icon.png file name and put it into the images folder.
  • Widget manifest file- Use the name manifest.json to describe the widget’s content.

Does your widget need a panel?

For more information on what a panel is, see the Theme Development section for more details.

Two types of widgets are supported. One is a widget without a panel (such as Scalebar widget, Overview widget, and so on) and another is anin panel widget. Therefore, you make a decision, before coding, about whether your widget needs a panel or not. There are some differences between them:

  • Widget without a panel is not allowed in a widget pool. It’s only available in preload widgets.
  • If a widget is without a panel, the app container opens the widget when the app starts.
  • If a widget is in a panel, the app container creates an action button identified by the widget icon. When the widget icon is clicked, the widget opens in the panel.

You can set the inPanel property in the widget’s manifest.json. For more details, see Package your widget.

Create the files for the widget

A widget at a minimum requires one file, the JavaScript file that defines it. However, for a more full-featured widget, there are multiple files to define it, including the HTML template, i18n support, styles, and so on. All of these will be demonstrated.

First, to keep your widget files, create a folder (samplewidgets/Demo). Next, create the following set of folders and files in the folder:

demo widget folder

  • The JavaScript file that defines the widget (Widget.js).
  • Template file that defines the widget’s UI (Widget.html)
  • The widget’s Configuration file (config.json).
  • The widget’s i18n strings file (nls/strings.js).
  • The widget’s style file (css/style.css).

Extend the BaseWidget class

JavaScript is not a classical language. It is a prototypical object oriented language. As such, to make most developers comfortable with developing widgets, the ArcGIS WebApp Builder uses Dojo’s functions to create and extend classes. The ArcGIS WebApp Builder defines the BaseWidget class from which you create the child class, Widget.

Open Widget.js in a text editor. The basic code for extending BaseWidget is:

define(['dojo/_base/declare', 'jimu/BaseWidget'],
function(declare, BaseWidget) {
  //To create a widget, you need to derive from BaseWidget.
  return declare([BaseWidget], {
    // DemoWidget code goes here 

  });
});

This code:

  • Declares the DemoWidget class as a child class of BaseWidget.

For more information, see http://dojotoolkit.org/documentation/tutorials/1.8/declare/.

Set the required properties

The following properties are required by the programming model:

  • baseClass- The widget’s root element CSS class name. Use the name, jimu-widget-widgetname.

The code looks like the following:

define(['dojo/_base/declare', 'jimu/BaseWidget'],
function(declare, BaseWidget) {
  //To create a widget, you need to derive from BaseWidget.
  return declare([BaseWidget], {
    // DemoWidget code goes here 
    baseClass: 'jimu-widget-demo'
  });
});

Define the widget’s template (UI)

ArcGIS WebApp Builder widgets have an HTML template. This template defines the widget’s UI.

Open the Widget.html file in a text editor. Replace it with this:

<div>
    <div>I am a demo widget.</div>
</div>

At this point, test your widget. Open config-demo.json (in stemapp/sample-configs folder). Find widgetPool->widgets, and add a new widget element like this:

{
  "label": "demo",
  "uri": "widgets/samplewidgets/Demo/Widget"
}

Start the ArcGIS WebApp Builder through http://you host/webapp/?config=sample-configs/config-demo.json ,and click the icon. The widget appears like the following:

demo widget UI

Note
By default, the widget’s template does not support dijit in the template. If you need to use dijit in the template, add dijit/_WidgetsInTemplateMixin into your required list, and mixin this class into your widget. Meanwhile, ensure that you have required all of the dijits used in the template. For more information, see Creating Template-based Widgets

Make it configurable

Currently, there are no configuration options for the Demo widget.

To change that, open config.json in the widget folder in a text editor. Add some JSON-structured text so that you can pass the config to your widget:

{
    "configText":"abcdefg"
}

Alter the HTML template to use the config that you have read from your config file.

<div>
    <div>I am a demo widget.</div>
    <div>This is configurable.[${ config.configText}]</div>
</div>

Now, the Demo widget looks like the following:

configured demo widget

The ${configData.configText} marker in the template is automatically substituted with the values in the config.json file.

Add i18n support

Currently, in the Demo widget, there are some hard-coded English language strings:

  • I am a demo widget.
  • This is configurable.

To internationalize the UI, generally you should isolate these strings in a separate language-specific resource file and reference the strings by their identity. Dojo provides complete i18n support, which is sensitive to user settings in the browser. For example, if Chinese translation is defined, and a user visits your web application with their browser language code set to zh-cn, they should automatically get the Chinese UI. For more information, see http://dojotoolkit.org/documentation/tutorials/1.8/i18n/.

The first step is to abstract the user interface strings to the default resource file. The user determines the translation of these strings.

Open the nls/strings.js file with a text editor. Add the following:

define({
    root:{
        label1: "I am a demo widget.”
        label2: "This is configurable."
    },
    "zh-cn": true    
});

Create a folder named zh-cn and create a strings.js file in it. The following is the content:

define({
    label1 : "我是一个演示widget。",
    label2 : "这里可以配置。"
});

Apply the changes to the template by removing the hard-coded English language and replacing it with markers:

<div>
    <div>${nls.label1}.</div>
    <div>${nls.label2}.[${configData.configText}]</div>
</div>

Reload your ArcGIS WebApp Builder application. This time, add a URL parameter, locale=zh-cn, or you change the browser’s locale configuration to view the change.

localized

To support specific languages, create folders under the nls/ folder, named by the language code (for example, en, fr, ru). Copy the strings.js file to that folder and update the content to reflect the language for that code.

Make it user friendly

On the HTML page, a CSS file is used to layout the page, making it user friendly. The recommended way is to use a separate style file to write the CSS rules. Put the widget CSS in the css/style.css file.

Open the css/style.css file and add the following code:

.jimu-widget-demo div:first-child{
  color: red;
}

Note that all of the selectors in the style.css file should contain the base CSS class to avoid name conflict.

Open the viewer. The widget resembles the following:

demo widget

Let the widget fit the theme

For more information about themes, see the Theme Development session.
By default, all of the CSS rules you write are applied in all themes. If you want to apply some CSS rules for a specific theme or theme style, write your CSS rule like this:

.themeName .styleName {your selector}{  
}

Access a map

The ArcGIS WebApp Builder is a map-centric application. It provides map property defined in the BaseWidget class to access the map. You can access the map property through this.map. . The widget’s map property is a type of esri.Map from ArcGIS JavaScript API, configured in the config.json file. You can access all the map features provided by ArcGIS JavaScript API. Code the widget just like writing a regular ArcGIS JavaScript application.

When a widget is instantiated, the map passes into it. As a result, you can access a map property in the postCreate or startup methods.

Modify the UI template and add a div tag to display the map id property:

<div>
    <div>${nls.label1}.</div>
    <div>${nls.label2}.[${configData.configText}]</div>
      <div data-dojo-attach-point="mapIdNode"></div>
</div>

Add JavaScript code to access map:

startup: function(){
  this.inherited(arguments);
  this.mapIdNode.innerHTML = 'map id:' + this.map.id;
}

Communication to the app container

Response to the app container

The widget is a dojo dijit; therefore, when a widget is instantiated, it goes through the full life cycle of a dijit, such as constructor, postCreate, startup and so on. For more information, see http://dojotoolkit.org/documentation/tutorials/1.9/understanding_widgetbase/

In addition to the dojo dijit’s life cycle functions, the widget has other callback functions that you can use:

onOpen- Called each time the widget opens. When a widget is instantiated, this method is called after startup.

onMaximized- Called when the widget is maximized. This method may never be called in some panels that do not have a maximize/minimize state.

onMinimized- Called when the widget is minimized. This method may never be called in some panels that do not have a maximize/minimize state.

onClose- Called when the widget closes.

onSignIn- Called when a user signs in to the portal/AGOL.

onSignOut- Called when a user signs out from the portal/AGOL.

onPositionChange- Called when widget’s position (left, right, top, bottom, width, height) changes. The widget’s position may be changed when the user changes the layout in the builder.

resize- Called when the window resizes.

Widget properties

TThe following are additional properties to use in widgets:

Name Description
id The unique ID of the widget set in the config.json file or generated by the app container.
label Set in the config.json file
icon The widget’s icon URL
config The widget’s config object
map The map this widget works to
appConfig The app's main config.json file is stored here.
folderUrl The widget folder’s URL.
state The widget’s current state, that is, opened or closed.
windowState The widget’s current window state, that is, normal, maximized, or minimized.

Use the app container CSS classes and dijits

To implement a consistence UI style and make development work easier, the widget developer should use the CSS classes and dijits provided by the app container.

You can view these components from http://you host/webapp/jimu.js/tests/test-dijit.html and http://you host/webapp/jimu.js/tests/test-css.html. Note that these CSS classes and dijits will be added and updated as the app container evolves.

The CSS classes can be found in jimu.js/css/jimu.css.

Name Description
jimu-input Styled input tag
jimu-btn Styled button using div
Jimu-icon-btn Button with an icon in the center
Jimu-nav-bar Group of icon buttons
jimu-oe-row Odd even row


The dijits: (can be found in jimu.js/dijit)

Name Description
CheckBox N/A
RadioBtn N/A
DrawBox N/A
ColorPicker N/A
Popup N/A
ImageChooser N/A
TabContainer N/A
ExtentChooser N/A
Message N/A
LayerFieldChooser N/A
PopupConfig N/A
SymbolChooser N/A

Make the widget responsive

The jimu.js file does not only support a responsive UI layout but also provides functions for developers to develop responsive widgets.

There are two ways to archive the responsive goal: CSS and layout dijit .

The CSS classes can be found in jimu.js/css/jimu.css.

Name Description
jimu-r-row One row of the layout
col-1-2 The width is half of its parent
col-1-3 The width is one third of its parent
col-2-3 N/A
col-1-4 N/A
col-3-4 N/A


The dijits can be found in jimu.js/dijit

Name Description
TileLayoutContainer N/A


If both of them cannot meet your requirements, follow the responsive UI best practices.

Communication between widgets

As the requirement of reading or sending data between widgets is common, the BaseWidget class supports this programming model.

In the constructor of the BaseWidget class, it subscribes the publishData, dataFetched, and noData events. Meanwhile, the BaseWidget class provides the publishData and fetchData methods.

If you want the widget to publish data, call the publishData method. If you want the widget to receive data from another widget, call the fetchData method, and write code to override the onData and onNoData methods to read data.

Use the dojo dijit in widget

The widget is a dojo dijit, which derives from the BaseWidget dijit; therefore, you can use the existing dijit as normal. With performance considerations, don’t mixin the _WidgetsInTemplateMixin in the BaseWidget. If you need to use dijit in the widget’s UI template file, mixin this class and require all of the dijits that you use in the template file. For more information, see Creating Template-based Widgets for more information.

Make the widget configurable in the builder

If the widget is configurable, the user can change the widget’s behavior by editing the config.json file. For a better user experience, the widget should provide a config UI to config itself when it is configured in the builder.

These are the conventions the widget should follow:

  1. Create a folder named setting to hold all of the setting related files.
  2. Create a Setting.js file in the setting folder to hold the config logic. This class should inherit from BaseSetting class. In this class, there is a config property that holds the widget config data.
  3. Also, this class should override two methods: getConfig, return the config data input by the user and setConfig to initialize the widget setting page depending on the widget config data.
  4. Create a Setting.html file in the setting folder to hold the config UI
  5. Create a strings.js file in the setting /nls folder if the config needs to support internalization.
  6. Create a style.css file in the setting /css folder to hold the css property.

During development, you can use http://your host/webappbuilder/?appid=stemapp to directly access your widget.

Package your widget

The widget is easily packaged and shared. As a result, all of the widget contents are placed in the widget folder with a description file named, manifest.json, which is a JSON object and contains following properties:

Attribute Type Description Required Default
name String The name identifies the widget. The name should be the same as the folder name under the widgets folder. Y N/A
2D Boolean Determines if the widget supports 2D N True
3D Boolean Determines if the widget supports 3D. N False
platform String Should be HTML. Y N/A
version String The format is 0.0.1. Y N/A
author String N/A N N/A
description String N/A N N/A
copyright String N/A N N/A
license String N/A N N/A
properties Object See the following Properties table. N N/A


Properties table for widgets:

Attribute Type Description Required Default
inPanel Boolean The widget displays in a panel by default. The developer can change this behavior. If it's not in a panel, the widget displays directly. N true
hasLocale Boolean The framework loads the i18n files by convention. N true
hasStyle Boolean N/A N true
hasConfig Boolean N/A N true
hasUIFile Boolean N/A N true
hasSettingPage Boolean N/A N true
hasSettingUIFile Boolean N/A N true
hasSettingLocale Boolean N/A N true
hasSettingStyle Boolean N/A N true
isController Boolean If the widget is a controller widget, set this property to true. N false


After this file is complete, can zip the widget and share the package to the widget repository.

Theme development

Concepts

A theme defines panels, styles, and layouts. One app can include more than one theme, but can only use one theme while running.

A theme is a folder named as the theme name. It contains the following files:

  • Similar with a widget, a theme must have an icon file named icon.png, which is under the images folder.

  • A common.css file under the theme folder. It contains style content that is common for all styles.

  • A theme can include multiple styles in the styles folder. Each style is a folder that named as the style name. Each style must have a style.css file. A style named default is necessary.

  • A theme can include multiple panels in the panels folder. Each panel is a folder named as the panel name. Each panel must have a Panel.js file.

  • • A theme can include multiple layouts in the layouts folder. Each layout is a folder named as the layout name. Each layout must have a config.json file and an icon.png file. A layout named default is necessary.

  • A manifest.json file to describe the theme content. The followings are its properties:

Attribute Type Description Required Default
name String The theme’s identity. It must be the same as the theme folder name. Y N/A
label String The displayed text for the theme. Y Theme's name
styles [] A list of theme styles. Each style has a name, description, and styleColor properties. Y N/A
panels [] A list of theme panels. Each panel has a name and description properties. Y N/A
layouts [] A list of theme layouts. Each layout has a name and description properties. A layout is a configuration template file, which contains some widget configurations but leaves the uri property empty. Y N/A
version String The version format is 0.0.1. Y N/A
author String N/A N N/A
description String N/A N N/A
copyright String N/A N N/A
license String N/A N N/A


ArcGIS WebApp Builder provides two out-of-box themes, FoldableTheme and TabTheme. You can develop custom themes if these themes do not meet your requirements.

Create a Demo theme

In the created Demo theme, there is one panel, two styles, and two layouts. The panel is called SimpleBorderPanel, and has a basic border. One style, called default, has red as a main color, and another called black, has black as a main color. One layout called default, places one widget on the left side, and is the other called right, places one widget on the right side.

Notes:

  • The source code of the Demo theme is placed under stemapp/themes/DemoTheme in our source code repository. You can try the Demo theme in the builder.
  • If you create a custom theme, put your theme folder under the theme repository folder (stemapp/themes by default).

Create files for the theme

As described above, to create a theme, you need to create some necessary files under the theme folder. Here is the file structure of the Demo theme:

DemoTheme

Edit the manifest.json

The manifest.json file describes the theme’s content, and the builder reads this file to get the theme’s content. Based on the specification described above, update the manifest.json file as follows:

{
  "name": "DemoTheme",
  "panels": [
    {
      "name": "SimpleBorderPanel",
      "description": "This is a panel with a border"
    }
  ],
  "styles": [
    {
      "name": "default",
      "description": "this is default style",
      "styleColor": "red"
    },
    {
      "name": "black",
      "description": "this is black style",
      "styleColor": "#000000"
    }
  ],
  "layouts": [
    {
      "name": "default",
      "description": "this is the left layout"
    },
    {
      "name": "right",
      "description": "this is the right layout"
    }
  ],
  "version": "0.0.1",
  "author": "Esri R&D Center Beijing",
  "description": "",
  "copyright": "",
  "license": "http://www.apache.org/licenses/LICENSE-2.0"
}

Create the panel

A panel is a UI element that used to display the widget’s content. Multiple widgets can use the same panel. However, the widget does not display directly on the panel. It is put in the WidgetFrame, then the widget frame displays on the panel. One widget frame holds one widget, and one panel can contain more than one widget frame. The following image gives you a general picture about the relationships of the panel, widget frame, and widget.

Panel

Developing a panel is the hardest work for a custom theme. To create a panel, you need JavaScript, CSS, and HTML knowledge. It is also beneficial to understand the dojo’s layout knowledge.

To create a panel, create a class that derives from BaseWidgetPanel. If the default widget frame meets your requirements, create a frame class that derives from BaseWidgetFrame.

You can override some functions when you create your panel:

  • createFrame- This function returns the widget frame object.
  • reloadWidget- This function is called by the builder when the widget is modified.

The meaning of the following functions is the same as widget:

  • onOpen
  • onClose
  • onMaximize
  • onMinimize
  • onNormalize

Create SimpleBorderPanel

Because the SimpleBorderPanel is very basic, extend the BaseWidgetPanel without adding any new features. See the following code:

define(['dojo/_base/declare',
  'jimu/BaseWidgetPanel'
],
function(declare, BaseWidgetPanel) {
  return declare([BaseWidgetPanel], {
    baseClass: 'jimu-widget-panel jimu-border-panel',
  });
});

For more information about panels, see BaseWidgetPanel.

Create the styles

You need to write some style (CSS) files to make the theme more beautiful. In the style files, you can override the styles in jimu.css, and write the styles that your panel needs as well. Place the common styles (used by all of the styles) in the common.css file, and the specific styles in the corresponding style.css files.

There should be a style named default, to use when the theme is selected in the builder.

Edit teh default style

Because the default style’s main color is red, use the following style:

.jimu-border-panel{
  border: 1px solid red;
}

Edit the black style

.jimu-border-panel{
  border: 1px solid black;
}

Create the layouts

A layout is a config template file, which contains some widget config properties but leaves the uri property empty. When the app’s layout is changed, the builder does the following:

  • For preload widgets, use the panel and position properties in the new layout to replace the panel, and position properties in the old layout by order. If the widget count is not the same, ignore the rest.
  • For a widget pool, replace the group’s panel property by order.
  • For a map, replace the position property.

There should be a layout named default. This layout is used when the theme is selected in the builder to create the app config object.

Edit default layout

{
  "preloadWidgets": {
    "panel": {
      "uri": "themes/DemoTheme/panels/SimpleBorderPanel/Panel"
    },
    "widgets": [{
      "label": "Scalebar",
      "uri": "widgets/Scalebar/Widget",
      "position": {
        "left": 25,
        "bottom": 25
      }
    }, {
      "label": "Coordinate",
      "uri": "widgets/Coordinate/Widget",
      "inPanel": false,
      "position": {
        "left": 200,
        "bottom": 10
      }
    }, {
      "label": "Select a basemap",
      "uri": "widgets/BasemapGallery/Widget",
      "inPanel": true,
      "position": {
        "left": 45,
        "top": 5,
        "width": 430,
        "height": 520
      }
    }, {
      "position": {
        "left": 95,
        "top": 5,
        "width": 400,
        "height": 410
      }
    }]
  },

  "map": {
    "position": {
      "left": 0,
      "top": 0,
      "right": 0,
      "bottom": 0
    }
  }
}

Edit right layout

{
  "preloadWidgets": {
    "panel": {
      "uri": "themes/DemoTheme/panels/SimpleBorderPanel/Panel"
    },
    "widgets": [{
      "label": "Scalebar",
      "uri": "widgets/Scalebar/Widget",
      "position": {
        "left": 25,
        "bottom": 25
      }
    }, {
      "label": "Coordinate",
      "uri": "widgets/Coordinate/Widget",
      "inPanel": false,
      "position": {
        "left": 200,
        "bottom": 10
      }
    }, {
      "label": "Select a basemap",
      "uri": "widgets/BasemapGallery/Widget",
      "inPanel": true,
      "position": {
        "left": 45,
        "top": 5,
        "width": 430,
        "height": 520
      }
    }, {
      "position": {
        "right": 95,
        "top": 5,
        "width": 400,
        "height": 410
      }
    }]
  }
}

Try the Demo theme in the builder

Start the builder and create a new app. If no errors occur, the Demo theme shows in the Themes tab.

  1. Click the Demo theme.
  2. Click the Layout icon to switch layouts.
  3. Open the BasemapGallery widget.
  4. Click the style icon to switch styles.

During development, use http://your host/webappbuilder/?appid=stemapp to access your theme directly.