Programming patterns

Attributes and properties

Component HTML attributes and JavaScript properties, while similar in concept, have some key differences. HTML attributes are always strings. Even when setting what seems like a number, the attribute value is still a string. In HTML, the presence of an attribute means it is true, and its absence means it is false. Attributes are written in kebab-case, while properties are in camelCase.

Use dark colors for code blocksCopy
1
<arcgis-layer-list reference-element="my-map" drag-enabled selection-mode="multiple"/>

On the other hand, JavaScript properties can be any valid JavaScript data type, including strings, booleans, numbers, arrays, objects, functions, and more. Most properties have an associated attribute, but not all. If a property is any type besides a string, number, or boolean, it will not have an associated attribute.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Get a reference to the arcgis-layer-list component
const arcgisLayerList = document.querySelector("arcgis-layer-list");

// Set properties with various data types

// arcgis-map component
arcgisLayerList.referenceElement = document.querySelector("#my-map");
// boolean
arcgisLayerList.dragEnabled = true;
// function
arcgisLayerList.listItemCreatedFunction = (event) => {
  const { item } = event;
  if (item.layer.type != "group") {
    item.panel = {
      content: "legend"
    };
  }
};
// string
arcgisLayerList.selectionMode = "multiple";
// object
arcgisLayerList.visibleElements = {
  ...arcgisLayerList.visibleElements,
  ...{
    statusIndicators: false
  }
};

Watch for changes

Watching properties or attributes on a component can help make your application more responsive and easier to maintain. You can watch for changes using a component's events, a mutation observer or a proxy.

Using component events

Components carry information about their state and may emit this information as events to notify the application of changes. Events are typically emitted when the user interacts with the component, or when the component changes state. One can listen for events using the addEventListener method. The event's payload contains information about the event, such as the action that was triggered, the item that was clicked, or the new state of the component.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
const arcgisLayerList = document.querySelector("arcgis-layer-list");
arcgisLayerList.addEventListener("layerListTriggerAction", async (event) => {
  // event.detail is used here since the event type is CustomEvent<LayerListTriggerActionEvent>
  const { action, item } = event.detail;
  await item.layer.load();
  if (action.id === "information") {
    // do something;
  }
});

Map interactions such as panning, zooming, clicking and dragging can be tracked using events. To watch for view related property changes (zoom, scale, center, extent etc.) on the <arcgis-map/> component, use the arcgisViewChange event.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
const map = document.querySelector("arcgis-map");
map.addEventListener("arcgisViewChange", (event) => {
  // event.target provides a reference to the object that dispatched the event
  // event.target is used here since the event type is CustomEvent<void>
  // void means that there are no details to show
  const { zoom } = event.target;
  console.log(`The zoom is ${zoom}`);
})

Additionally, the arcgisViewReadyChange event can be used to watch for when the view is ready or if the view's map or scene have been replaced

Use dark colors for code blocksCopy
1
2
3
4
const map = document.querySelector("arcgis-map");
map.addEventListener("arcgisViewReadyChange", () => {
  console.log(`The view is ready`);
})

Using a mutation observer

A mutation observer is useful for watching changes that are reflected on the DOM tree. JavaScript objects and arrays cannot be watched with a mutation observer because they are not part of the DOM, and not every attribute on a component is reflected, meaning that not every attribute will trigger a mutation observer.

Changes that are reflected on the DOM can be visibly observed in a browser's developer tools. When a map is panned, the <arcgis-map/> component's updating attribute will appear only for a few seconds.

Before panning the map:

Use dark colors for code blocksCopy
1
<arcgis-map item-id="05e015c5f0314db9a487a9b46cb37eca"></arcgis-map>

After panning the map:

Use dark colors for code blocksCopy
1
<arcgis-map item-id="05e015c5f0314db9a487a9b46cb37eca" updating></arcgis-map>

Below, the mutation observer will fire a callback function when any of the <arcgis-map/> component's attributes are modified.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const map = document.querySelector("arcgis-map");
const observer = new MutationObserver((mutations, observer) => {
  for (let mutation of mutations) {
    // Console.log when item id changes
    if (mutation.type === 'attributes' && mutation.attributeName === 'item-id') {
      console.log(`Mutation observer: item id changed to ${arcgisMap.getAttribute('item-id')}`);
    }
  }
});

// Start observing the map's attributes for changes, such as the item id
observer.observe(map, { attributes: true });

// Change the item id after 1 second
setTimeout(() => {
  map.itemId = "e691172598f04ea8881cd2a4adaa45ba"
}, "1000");

Visit the component API reference of your component to see which attributes are reflected.

Using a proxy

A proxy is useful for observing changes to the properties of a component. In the example below, the proxy will fire a callback function when any of the <arcgis-map/> component's properties are modified. The set method only applies to properties that you explicity set in your code.

Since the example below needs an instance of WebMap, both the ESM and AMD approach for importing the WebMap are covered. The WebMap is imported at the top in ESM, but in AMD, the WebMap is imported inside an async function using the $arcgis global. The $arcgis global is a new promise-based way of importing modules in ArcGIS Maps SDK for JavaScript AMD projects without the need for require. The $arcgis global is available in the ArcGIS Maps SDK for JavaScript 4.28 and later for AMD projects.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import WebMap from "@arcgis/core/WebMap.js";

const map = document.querySelector("arcgis-map");

// A handler for the proxy to define which operations will be intercepted
// and how to redefine them
const handler = {
  // obj - the object being proxied (in this case, the map)
  // prop - the property of the object that is being set
  // value - the new value of the property
  set: function whenChange(obj,prop,value) {
    obj[prop] = value
    console.log(`Proxy: the ${prop} property was changed`)
    return true
  }
}

let proxy = new Proxy(map, handler);

// Change to a different web map
proxy.map = new WebMap({ portalItem: { id: "e691172598f04ea8881cd2a4adaa45ba"} });

Associate components with a Map or Scene

The Map and Scene components are parent containers for building interactive 2D and 3D visualization experiences. Other components from the @arcgis/map-components package can be associated with a Map or Scene component to provide additional functionality, such as adding a legend, layer list, search, and more. There are two methods to associate components from @arcgis/map-components package to a Map or Scene component. The first method involves including the component as a child element of the Map or Scene component

Use dark colors for code blocksCopy
1
2
3
<arcgis-map item-id="05e015c5f0314db9a487a9b46cb37eca">
  <arcgis-legend position="bottom-right" />
</arcgis-map>

The second is to use the reference-element attribute on the component. By passing the id of the Map or Scene component into this attribute, you can position components from the @arcgis/map-components package anywhere in the DOM while still maintaining a connection to the Map or Scene.

Use dark colors for code blocksCopy
1
2
<arcgis-map id="my-map" item-id="05e015c5f0314db9a487a9b46cb37eca" />
<arcgis-legend reference-element="#my-map" />

Local assets

For most use cases, it is recommended to use the APIs assets from the ArcGIS CDN. One advantage of using the CDN is the APIs CSS styles will not need to be bundled on-disk with your local build. The assets include styles, images, web workers, wasm and localization files.

If you need to manage the API's assets locally, copy them into your project from /node_modules/@arcgis/core/assets, and then set setAssetsPath to ensure the asset paths are resolved correctly. A simple way to accomplish this is to configure an npm script that runs during your build process. For example, on a Mac or Windows terminal you could use cpx2.

Here’s a React example to copy the assets. Check your framework or bundler documentation for best practices on using npm scripts or plugins for copying files:

package.json

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
{
  "script": {
    "start": "npm run copy && react-scripts start",
    "build": "npm run copy && react-scripts build",
    "copy": "cpx ./node_modules/@arcgis/core/assets ./public/assets"
  }
}

index.js

Use dark colors for code blocksCopy
1
2
3
// Set the asset path for all the components
import { setAssetPath } from "@arcgis/coding-components/dist/components";
setAssetPath("./public/assets");

Configure global properties

You can use the global esriConfig variable to configure global properties of the JavaScript Maps SDK (API and components), such as the portalUrl.

Set the portalUrl in an AMD application

Importing esri/config is necessary for configuring the global esriConfig object in AMD applications.

AMD
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<html>
  <head>
    <!-- Load the ArcGIS Maps SDK for JavaScript -->
    <link rel="stylesheet" href="https://js.arcgis.com/~4.29.0/esri/themes/dark/main.css" />
    <script src="https://js.arcgis.com/~4.29.0/"></script>
    <script>
      require(["esri/config"], (esriConfig) => {
        esriConfig.portalUrl = "https://myHostName.esri.com/arcgis";
      });
      // Optional: $arcgis global instead of require
      // async function load() {
      // 	const esriConfig = await $arcgis.import("esri/config");
      // 	esriConfig.portalUrl = "https://myHostName.esri.com/arcgis";
      // }
      // load();
	</script>
    <!-- Load map components -->
    <script type="module" src="https://js.arcgis.com/map-components/~4.29.0/arcgis-map-components.esm.js"></script>
  </head>
  <body>
    <arcgis-map item-id="d5dda743788a4b0688fe48f43ae7beb9">
      <arcgis-legend position="bottom-left"></arcgis-legend>
    </arcgis-map>
  </body>
</html>

Set the portalUrl in an ESM application

Importing @arcgis/core/config is necessary for configuring the global esriConfig object in ESM applications. Web maps hosted on a different portal can be initialized before being passed to the arcgis-map component:

ESM
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import esriConfig from "@arcgis/core/config";
import WebMap from "@arcgis/core/WebMap";
import IdentityManager from "@arcgis/core/identity/IdentityManager";
import OAuthInfo from "@arcgis/core/identity/OAuthInfo";

const portalUrl = "https://myHostName.esri.com/arcgis";
const mapElem = document.querySelector("arcgis-map");

esriConfig.portalUrl = portalUrl;

// Bonus: register OAuth info
IdentityManager.registerOAuthInfos([
  new OAuthInfo({
    appId: "...",
    portalUrl
  });
]);

const webmap = new WebMap({
  portalItem: {
    id: "..."
  }
})

// Pass the webmap to the `arcgis-map` component
mapElem.map = webmap;

Localization

The language and direction of some web components, such as @arcgis/charts-components and @arcgis/coding-components, can be inherited from the root of the HTML document in the host application, the component itself, or the component's closest parent element. This is a bottom up approach. In cases where a language and direction are not provided, the component will default to left-to-right (ltr) and English (en). See locale support for the full list of supported languages.

Setting the language

Use the ISO language code for setting the language in the lang attribute.

Use dark colors for code blocksCopy
1
<html lang="fr"></html>

Setting the direction

You only need to do this for Arabic and Hebrew.

Use dark colors for code blocksCopy
1
<html dir="rtl" lang="he"></html>

Programming patterns in frameworks

The documentation above covers cases where the application's code is mainly written in a vanilla JavaScript. When it comes to frameworks, such as React, Angular, or Vue, using a framework's coding patterns to interact with the components may be the preferable approach as a lot of the work can be done directly on the component.

React

Below is an example of how to set properties and listen for events on the <arcgis-map/> component in a React application.

index.tsx
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from "react";
import ReactDOM from "react-dom/client";

import { ArcgisMap, ArcgisSearch, ArcgisLegend } from "@arcgis/map-components-react";

const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
  <React.StrictMode>
    <ArcgisMap
      item-id="d5dda743788a4b0688fe48f43ae7beb9"
      center={[-100.4593, 36.9014]}
      onArcgisViewReadyChange={(event: any) => {
        console.log('Map View ready', event);
      }}
    >
      <ArcgisSearch position="top-right"></ArcgisSearch>
      <ArcgisLegend position="bottom-left"></ArcgisLegend>
    </ArcgisMap>
  </React.StrictMode>
);

Get started with the map components React template

Angular

Below is an example of how to set properties and listen for events on the <arcgis-map/> component in an Angular application.

app.component.html
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
<arcgis-map
  item-id="d5dda743788a4b0688fe48f43ae7beb9"
  [center]="[-100.4593, 36.9014]"
  (arcgisViewReadyChange)="onArcgisViewReadyChange($event)">
  <arcgis-expand>
    <arcgis-search position="top-right"></arcgis-search>
  </arcgis-expand>
  <arcgis-legend position="bottom-left"></arcgis-legend>
</arcgis-map>
app.component.ts
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  title = 'map-components-angular';
  onArcgisViewReadyChange(event: any) {
    console.log('Map View ready', event);
  }
}

Get started with the map components Angular template

Vue

Below is an example of how to set properties and listen for events on the <arcgis-map/> component in a Vue application.

App.vue
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
  <arcgis-map
    item-id="d5dda743788a4b0688fe48f43ae7beb9"
    v-bind:center="[-100.4593, 36.9014]"
    v-on:arcgisViewReadyChange="
      (event) => {
        console.log('Map View ready', event);
      }
    "
  >
    <arcgis-search position="top-right" />
    <arcgis-legend position="bottom-left" />
  </arcgis-map>
</template>

Get started with the map components Vue template

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