popups

This bundle allows to configure the general behavior of popups and provides the mechanism for adding a default popup to layers and stores that do not have a dedicated popup configuration.

The bundle also provides interfaces to implement custom popup content and actions.

For more details, see the API documentation.

Usage

Default popups

To use default popups in an app, add the popups-default bundle to the app. For configuration details, see popups-default.

The popup bundle adds the property defaultPopupType with value default to every MapImageLayer sublayer, FeatureLayer, and store which do not declare a popup template. To disable this behavior, set defaultPopupEnabled to false on the layer.

The PopupDefinitionFactory implementation for the defaultPopupType value default is located in the popups-default bundle. To use a custom popup implementation as default, see Use your own popup implementation as a default.

Popups for OGC WMS

The popup bundle sets the property popupEnabled to true for all WMS sublayers to automatic enable the popups for this type of service. To disable popups for a single WMS sublayer, set the property queryable to false on the WMS sublayer. To fully disable popups for a WMS service, set the property popupEnabled to false on the WMS service.

The support for WMS layer is limited to Custom Actions. It is not possible to customize the popup content of a WMS by configuration.

Individual popups

For an overview about how to configure individual popups, see the Individual popups section in the product documentation.

Custom popups

This bundle provides an API to integrate custom popup content. To use a custom popup, do the following:

  1. Integrate one or more bundles which provide custom popup types. See Implement a PopupDefinitionFactory.
  2. Reference a popup type in a layer's or store's popupTemplate configuration:
    {
        "load": {
            "allowedBundles": [
                ...
                "popups",
                "my-popups"
                ...
            ]
        },
        "bundles": {
            "agssearch": {
                "AGSStore": [
                    {
                        ...
                        "popupTemplate": {
                            "popupType": "custom-type"
                        }
                    }
                ]
            },
            "map-init": {
                "Config": {
                    "map": {
                        "layers": [
                            {
                                ...
                                "popupTemplate": {
                                    "popupType": "my-popup"
                                }
                            }
                        ]
                    }
                }
            }
        }
    }
    

Custom actions

This bundle provides an API to integrate custom actions. To use custom actions, do the following:

  1. Integrate one or more bundles which provide custom action types. See Implement a custom ActionFactory.
  2. Reference an action type in a layer's popupTemplate configuration:
    {
        "load": {
            "allowedBundles": [
                ...
                "popups",
                "my-actions"
                ...
            ]
        },
        "bundles": {
            "map-init": {
                "Config": {
                    "map": {
                        "layers": [
                            {
                                ...
                                "popupTemplate": {
                                    "customActions": ["my-action"]
                                }
                            }
                        ]
                    }
                }
            }
        }
    }
    

To add a custom action to a WMS layer, use the following configuration:

{
    "bundles": {
        "map-init": {
            "Config": {
                "map": {
                    "layers": [
                        {
                            "id": "my-wms",
                            "type": "WMS",
                            "url": "https://example.com/WMS",
                            "popupTemplate": {
                                "customActions": ["my-action"]
                            }
                        }
                    ]
                }
            }
        }
    }
}

Configuration reference

The following sample shows all configurable properties and their default values:

"popups": {
    "Config": {
        // Default popup options
        "defaultPopupType": "default",
        "defaultPopupEnabled": true,

        // Popup behavior options
        "highlightEnabled": true,
        "autoCloseEnabled": false,
        "collapseEnabled": false,
        "visibleElements": {
            "featureNavigation": true,
            "closeButton": true
        },
        "includeDefaultActions": true,
        "dockingForced": false,
        "dockingDisabled": false,
        "dockEnabled": false,
        "dockPosition": "auto",
        "dockButtonEnabled": true,
        "dockBreakpoint": true
    }
}
Property Description
defaultPopupType ID of the default popup type.
defaultPopupEnabled Determines if default popups are enabled.
highlightEnabled Highlight the selected popup feature. (Details).
autoCloseEnabled Closes the popup when the View camera or Viewpoint changes. (Details).
collapseEnabled Indicates whether to enable collapse functionality for the popup. (Details).
visibleElements Turns individual display elements on or off. All elements are shown by default. (Details).
includeDefaultActions Turns default actions in the popup's UI on or off. True by default. (Details)
dockingForced Force all popups to be docked. See Force docking for all popups.
dockingDisabled Disable docking for all popups. See Disable docking for all popups.
dockEnabled Indicates whether the placement of the popup is docked to the side of the view. (Details).
dockPosition The position in the view at which to dock the popup. (Details).
dockButtonEnabled If true, displays the dock button. If false, hides the dock button from the popup. (Details).
dockBreakpoint Defines the dimensions of the View at which to dock the popup. (Details).

Constraints

Use cases

Force docking for all popups

To force docking of all popups, use the property dockingForced:

"popups": {
    "Config": {
        "dockingForced": true
    }
}

This is equal to declaring the following properties:

"popups": {
    "Config": {
        "dockEnabled": true,
        "dockButtonEnabled": false,
        "dockBreakpoint": false
    }
}

Disable docking for all popups

To disable docking for all popups, use the dockingDisabled property:

"popups": {
    "Config": {
        "dockingDisabled": true
    }
}

This disables the popup button and breakpoint and is equal to declaring the following properties:

"popups": {
    "Config": {
        "dockEnabled": false,
        "dockButtonEnabled": false,
        "dockBreakpoint": false
    }
}

Implement a custom popup definition factory

To implement a custom popup definition factory, implement the PopupDefinitionFactory interface as defined in the API documentation.

This requires to provide a CustomPopupDefinition which implements the PopupDefinition interface.

export default function CustomPopupDefinition() {
    return {
        resolvePopupTemplate(layerOrSublayer) {
            // Use the layer to get metadata for example about fields.
            // Create a custom PopupTemplate.
            return {
                title: "'{title}'",
                content: "objectId is '{objectid}'"
            };
        }
        resolvePopupTemplateForStore(store) {
            // Use the store to get metadata for example about fields.
            // Create a custom PopupTemplate.
            return {
                title: "'{title}'",
                content: "objectId is '{objectid}'"
            };
        };
    };
}

Next, create a CustomPopupDefinitionFactory which implements the PopupDefinitionFactory interface.

import CustomPopupDefinition from "./CustomPopupDefinition";
export default function CustomPopupDefinitionFactory() {
    return {
        getTypes() {
            return ["custom"];
        },
        createPopupDefinition(type) {
            switch (type) {
                case "custom":
                    return new CustomPopupDefinition();
                default:
                    throw new Error("unsuported type");
            }
        }
    };
}

Then, register an instance of this factory at the component system, that is provided as popups.PopupDefinitionFactory in the bundle's manifest.json file:

{
    "components": [
        {
            "name": "TweetablePopupDefinitionFactory",
            "provides": "popups.PopupDefinitionFactory"
        }
    ]
}

Implement a custom popup definition which provides custom widgets

If the features of a PopupTemplate are not sufficient, it is possible to create custom widgets using the following approach:

import ContentUpdateProxy from "./ContentUpdateProxy";

export default function CustomWidgetPopupDefinition() {
    return {
        resolvePopupTemplate(layer) {
            return {
                // Declare which fields should be fetched
                // These are provided as attributes inside the graphic
                outFields: ["objectid", "Name", "Description"],

                // title may contain attributes from the fields array
                title: "This is {Name}",

                // Define a content function
                // NOTE:
                //  * Can return a Promise(dojo/Deferred required in 4.7)
                //  * This is global window, be careful about that!
                content({graphic}) {
                    let widget = layer._$popup_widget;
                    if (!widget) {
                        widget = layer._$popup_widget = createWidget();
                        // widget is a dijit Widget
                        widget.startup();
                    }

                    // Use the proxy to handle content updates
                    // This ensures, that the correct content for every feature is shown,
                    // if the popup handles multiple feature hits
                    return ContentUpdateProxy(graphic, widget, (graphic) => {
                        updateWidgetContent(widget, graphic);
                    });
                }
            };
        }
        resolvePopupTemplateForStore(store) {

            // analogue to resolvePopupTemplate(layer)

        }
        cleanupPopupTemplate(layerOrStore) {
            let widget = layerOrStore._$popup_widget;
            delete layerOrStore._$popup_widget;
            widget && widget.destroyRecursive();
        }
    };
}

If the popup contains more than one feature, use the ContentUpdateProxy to ensure that the custom widget is always filled with the matching content of the selected feature. The callback function receives the popup graphic as a parameter and updates the widget.

Implement a custom action factory

To implement a custom action factory, implement the ActionFactory interface as defined in the API documentation. An action factory creates Action instances (see API documentation documentation for supported types).

export default function TweetActionFactory() {
    return {
        createAction(type) {
            return {
                id: "tweetablePopups.action.tweet",
                type: "button",
                title: "Tweet Feature",
                className: "esri-icon-share2",
                trigger(context) {
                    // Code to be performed, when the action is triggered,
                    // for example if someone clicks the link that is displayed in the popup.

                    const features = context.features; // All features that are hit by clicking on the map.
                    const selectedFeature = context.selectedFeature; // The selected and visible feature in the popup.
                    const location = context.location; // The point position where the popup is opened on the map.

                    // Tweet it: for example selectedFeature.attributes.description ...
                }
            };
        },
        getTypes() {
            return ["tweet"];
        }
    };
}

Then, register an instance of this factory at the component system, that is marked to provide the popups.ActionFactory interface in the bundle's manifest.json file:

{
    "components": [
        {
            "name": "TweetActionFactory",
            "provides": "popups.ActionFactory"
        }
    ]
}

Another option is to implement an Action class by extending from popups/Action:

import Action from "popups/Action";

class MyCustomAction extends Action {
    trigger(context) {
        // Do something when action is clicked
    }
}
export default MyCustomAction;

An instance of your class can then be returned by the createAction() method of your ActionFactory - remember to provide id and title properties in the constructor:

import MyCustomAction from "./MyCustomAction";

class MyCustomActionFactory {
    getTypes() {
        return ["mycustomaction"];
    }
    createAction(type) {
        return new MyCustomAction({
            id: type,
            title: "customAction"
        });
    }
}
export default MyCustomActionFactory;

Display actions depending on the selected feature

To display actions depending on the selected feature, provide the method isVisibleForFeature(feature) in your custom action implementation. To display the action for a feature, it has to return true. To hide the action for a feature, it has to return false.

If you do not provide that method, actions are visible for every feature of the layer the action is configured for.

Use the provided default popup only for specific layers or stores

To use the provided default popup from the popups-default bundle not in all layers and stores (without a configured popup template), but only in specific ones, choose one of the following options:

Use your own popup implementation as a default

To use another popup type as default popup, set the defaultPopupType property to the type that the custom popup definition factory provides. For example, to use the popup from the preceding sample, set defaultPopupType to tweetable and ensure, that the bundle containing the custom factory is used in your app.

Find a popup template for a store or layer

To locate popupTemplates for stores or layers, use the popups.PopupTemplateResolver service with the following declaration in a manifest.json file:

"references": [
    {
        "name": "popupTemplateResolver",
        "providing": "popups.PopupTemplateResolver"
    }
]

For usage in your component, see the API documentation.