Add layers to a map

Overview

You will learn: how to add layers to a map from a custom widget.

The map widget in ArcGIS Experience Builder automatically loads layers based on what web map it is configured to load. Depending on your workflow, you may want a custom widget to dynamically add a layer to the map based on user interaction with the widget.

In this tutorial, you will add a button to the widget to add a feature layer to the map.

Prerequisites

  1. Be sure to download, install, and configure Experience Builder.
  2. Complete the create a starter widget tutorial. It forms the base of this tutorial.

Steps

Get the starter widget

  1. Download the Starter Widget template here.

    If you have already completed the create a starter widget tutorial, you can start with that. Duplicate the widget folder within /client/your-extensions/widgets.

  2. In the ArcGIS Experience Builder folder, extract the zip into the following path: /client/your-extensions/widgets.

Change the widget name

  1. In the terminal where the npm start is running in the client folder, stop the script by pressing ctrl + c.

  2. In your file browser, go to the folder where Experience Builder was extracted.

  3. In the Experience Builder folder, expand the following path: /client/your-extensions/widgets.

  4. In the widgets folder, rename the starter-widget folder to add-layers-to-a-map.

  5. In the newly-renamed add-layers-to-a-map folder, open the manifest.json file in the code editor.

  6. In the code editor, modify the name property to add-layers-to-a-map.

    It is important that the name property of the manifest.json matches the name of the folder for your widget. You can also update the other metadata in the manifest.json file at this time, like the description of the widget, the author, etc.

          
    1
    2
    3
    4
    5
    6
     {
       // *** UPDATE  ***
       // "name": "starter-widget",
       "name": "add-layers-to-a-map",
       "type": "widget",
       "version": "1.6.0",
  7. After the version property in manifest.json, add a jimu-arcgis dependency. Declaring this allows the usage of ArcGIS API for JavaScript modules within the widget.

          
    1
    2
    3
    4
    5
    6
    {
       "name": "add-layers-to-a-map",
       "type": "widget",
       "version": "1.6.0",
       // *** ADD ***
       "dependency": "jimu-arcgis",

Implement the settings panel

A settings panel can be implemented to allow Experience authors to customize the widget. The settings panel appears in the right-hand sidebar when a widget is selected in ArcGIS Experience Builder. To create the panel, create a React component that uses React.PureComponent as a base class.

  1. In the widget root folder, create a config.json file that contains an empty object.

    At a later time, widget configuration parameters can be added to this object to store widget setting values.

  
1
2
{
}
  1. In the src folder, create another folder called setting.
  2. In the setting folder, create a setting.tsx file.
  3. Open the setting/setting.tsx file and include the following import statements.
   
1
2
3
/** @jsx jsx */
import { React, jsx } from "jimu-core";
import { AllWidgetSettingProps } from "jimu-for-builder";
  1. Add code to implement the component.
     
1
2
3
4
5
export default class Setting extends React.PureComponent<AllWidgetSettingProps<any>, any> {
  render() {
    return <div className="widget-setting-demo">This is your starter widget setting area!</div>;
  }
}
  1. In the terminal, stop (ctrl + c) (if applicable) and start the npm start script in the client folder.

Enable selecting a map view data source

In ArcGIS Experience Builder, there can be more than one Map Widget on the page at a time. Because of this, a custom widget must have a section of its Settings Panel that allows the author to choose which map widget to use.

  1. In the setting/setting.tsx file, include the MapWidgetSelector module from the jimu library.

     
    1
    import { MapWidgetSelector } from "jimu-ui/advanced/setting-components";
  2. Before the render function, define the onMapWidgetSelected function.

              
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     // *** ADD ***
     onMapWidgetSelected = (useMapWidgetIds: string[]) => {
       this.props.onSettingChange({
         id: this.props.id,
         useMapWidgetIds: useMapWidgetIds
       });
     };
     render() {
       return <div className="widget-setting-demo">This is your starter widget setting area!</div>;
     }
    
  3. In the render function, in the return() statement, add a tag representing the MapWidgetSelector.

            
    1
    2
    3
    4
    5
    6
    7
    8
     render() {
       return <div className="widget-setting-demo">
         <MapWidgetSelector
           useMapWidgetIds={this.props.useMapWidgetIds}
           onSelect={this.onMapWidgetSelected}
         />
       </div>;
     }
    

Access the map

In the previous step, the settings panel was enhanced to allow the Map widget to be selected. The map object can be accessed using the JimuMapViewComponent.

  1. In the widget.tsx file, add the JimuMapViewComponent and the JimuMapView type from the jimu library.

     
    1
    import { JimuMapViewComponent, JimuMapView } from "jimu-arcgis";
  2. Before the render function, set up the default state.

          
    1
    2
    3
    4
    5
    6
     export default class Widget extends React.PureComponent<AllWidgetProps<any>, any> {
     // *** ADD ***//
     state = {
       jimuMapView: null
     };
     render() {
  3. Add a function to update the state every time the JimuMapView data source changes.

    This function is called in the JimuMapViewComponent in the next step.

               
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    state = {
      jimuMapView: null
    };
    // *** ADD ***//
    activeViewChangeHandler = (jmv: JimuMapView) => {
      if (jmv) {
        this.setState({
          jimuMapView: jmv
        });
      }
    };
    
  4. In the render function, add the JimuMapViewComponent to the JSX markup.

    The first three lines of the added code ({this.props.hasOwnProperty...) are how to use conditionals in JSX. This is basically saying "only add the JimuMapViewComponent if the Experience author has chosen a valid map widget in the settings panel."

                    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     render() {
       return (
         <div className="widget-starter jimu-widget">
           {/* *** ADD *** */}
           {this.props.hasOwnProperty("useMapWidgetIds") &&
             this.props.useMapWidgetIds &&
              this.props.useMapWidgetIds[0] && (
               <JimuMapViewComponent
                 useMapWidgetId={this.props.useMapWidgetIds?.[0]}
                 onActiveViewChange={this.activeViewChangeHandler}
               />
             )
           }
         </div>
       );
     }
    

Add the button

Add a button to the UI of the widget that when clicked will add the layer to the map.

  1. In the code editor, add form and input tag elements in the existing div in the render function.

                         
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     render() {
       return (
         <div className="widget-starter jimu-widget">
           {this.props.hasOwnProperty("useMapWidgetIds") &&
             this.props.useMapWidgetIds &&
             this.props.useMapWidgetIds.length === 1 && (
               <JimuMapViewComponent
                 useMapWidgetIds={this.props.useMapWidgetIds}
                 onActiveViewChange={this.activeViewChangeHandler}
               />
             )
           }
           <!-- Add: -->
           <form onSubmit={this.formSubmit}>
             <div>
               <button>Add Layer</button>
             </div>
           </form>
         </div>
       );
     }
    
  2. Above the render function, create a new function called formSubmit. This function will get called when the user clicks the Add Layer button.

    `evt.preventDefault` prevents the page from reloading when the form is submitted.
        
    1
    2
    3
    4
    formSubmit = (evt) => {
      evt.preventDefault();
      // More here soon
    };
    

Add a layer

When the button is clicked, add the layer to the map.

  1. At the top of Widget.tsx, import the FeatureLayer class.

     
    1
    import FeatureLayer from "esri/layers/FeatureLayer";
  2. In the formSubmit function, update the code to create the Trailheads (points) feature layer and add it to the map.

    this.state.ds.view is an instance of MapView, so you can use any of those methods and properties, like the add() method here.

                 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    formSubmit = (evt) => {
      evt.preventDefault();
    
      // *** ADD ***
    
      // create a new FeatureLayer
      const layer = new FeatureLayer({
        url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trailheads_Styled/FeatureServer/0"
      });
    
      // Add the layer to the map (accessed through the Experience Builder JimuMapView data source)
      this.state.jimuMapView.view.map.add(layer);
    };
    

Test the widget

Once the code changes have been made, you can test your widget by running Experience Builder and viewing your experience.

  1. In a web browser, go to Experience Builder. e.g. https://localhost:3001

    If Experience Builder did not open a tab for you, browse to https://localhost:3001. If you get a "Invalid SSL Certificate" issue, click "Proceed Anyway".
  2. In Experience Builder, click Create New to create a new experience page.

  3. Click the Create button on the Blank scrolling template.

  4. Click the Insert widget button, and drag the new add-layers-to-a-map widget onto the experience.

    The widget may show an invalid icon right now. That's ok - you have not created one yet!
  5. In the widget settings panel, choose Map 1 from the map selection dropdown.

  6. In the Experience Builder toolbar, click Save then Preview and the experience will open in a new browser tab with your custom widget and a map.

Congratulations, you're done!

In the Experience Builder preview, click the button to add the layer to the map. Compare your widget with our completed widget.

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