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:
-
Integrate one or more bundles which provide custom popup types. See Implement a PopupDefinitionFactory.
-
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:
-
Integrate one or more bundles which provide custom action types. See Implement a custom ActionFactory.
-
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,
"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). |
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
- Default popups are provided for feature layers, map-image, and stores only.
- You have to define outfields on the layer, when defining custom popup definitions that need to access the features geometry.
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.
import Layer from "esri/layers/Layer";
import { PopupDefinition, PopupTemplateDefinition } from "popups/api";
import { Store } from "store-api/api";
export class CustomPopupDefinition implements PopupDefinition {
resolvePopupTemplate(layer: Layer): PopupTemplateDefinition | undefined {
// Use the layer to get metadata for example about fields.
// Create a custom PopupTemplate.
return {
title: "'{title}'",
content: "objectId is '{objectid}'"
};
}
resolvePopupTemplateForStore(
store: Store,
storeProperties: Record<string, any>
): PopupTemplateDefinition | undefined | Promise<PopupTemplateDefinition | undefined> {
// 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 { PopupDefinition, PopupDefinitionFactory } from "popups/api";
import { CustomPopupDefinition } from "./CustomPopupDefinition";
export class CustomPopupDefinitionFactory implements PopupDefinitionFactory {
getTypes(): string[] | Promise<string[]> {
return ["custom"];
}
createPopupDefinition(type: string): PopupDefinition | undefined | Promise<PopupDefinition | undefined> {
switch (type) {
case "custom":
return new CustomPopupDefinition();
default:
throw new Error(`unsupported type '${type}'`);
}
}
}
Export class in module.ts
file:
export { CustomPopupDefinitionFactory } from "./CustomPopupDefinitionFactory";
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": "CustomPopupDefinitionFactory",
"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 VueDijit from "apprt-vue/VueDijit";
import Graphic from "esri/Graphic";
import Layer from "esri/layers/Layer";
import { PopupDefinition, PopupTemplateDefinition } from "popups/api";
import ContentUpdateProxy, { WidgetProxy } from "popups/ContentUpdateProxy";
import { Store } from "store-api/api";
import Vue from "vue/types/umd.js";
import { CustomPopupWidget } from "./CustomPopupWidget.vue";
/**
* Type allowing to access the popup widget of a layer or store.
*/
type PopupWidgetAware<T> = T & {
_$popup_widget?: any;
}
function createWidget() {
return VueDijit(new Vue(CustomPopupWidget));
}
export class CustomWidgetPopupDefinition implements PopupDefinition {
resolvePopupTemplate(layerArg: Layer): PopupTemplateDefinition | undefined {
const layer = layerArg as PopupWidgetAware<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}: {graphic: Graphic}): WidgetProxy {
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) => {
// update the widget content
});
}
};
}
resolvePopupTemplateForStore(
store: Store,
storeProperties: Record<string, any>
): PopupTemplateDefinition | undefined | Promise<PopupTemplateDefinition | undefined> {
// analogue to resolvePopupTemplate(layer)
}
cleanupPopupTemplate(layerOrStoreArg: Layer | Store): void {
const layerOrStore = layerOrStoreArg as PopupWidgetAware<Layer | Store>;
const 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).
import { Action, ActionFactory } from "popups/api";
export class TweetActionFactory implements ActionFactory {
createAction(type: string): Action | undefined {
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(): string[] | Promise<string[]> {
return ["tweet"];
}
}
Export class in module.ts
file:
export { TweetActionFactory } from "./TweetActionFactory";
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";
import { ActionContext } from "popups/api";
export class MyCustomAction extends Action {
trigger(context: ActionContext) {
// Do something when action is clicked
}
}
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 { Action, ActionFactory } from "popups/api";
import { MyCustomAction } from "./MyCustomAction";
export class MyCustomActionFactory implements ActionFactory {
getTypes(): string[] | Promise<string[]> {
return ["mycustomaction"];
}
createAction(type: string): Action | undefined {
return new MyCustomAction({
id: type,
title: "customAction"
});
}
}
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:
- To exclude single layers or stores, set
popupEnabled
tofalse
for the particular layer or store. - Disable the default popup mechanism entirely by setting
defaultPopupEnabled
tofalse
. Then add the popups-default bundle to your app and set thepopupType
todefault
only for those layers and stores, you want the popup to be used for.
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.