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.
<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.
// 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 add
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.
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 arcgis
event.
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 arcgis
event can be used to watch for when the view is ready or if the view's map or scene have been replaced
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:
<arcgis-map item-id="05e015c5f0314db9a487a9b46cb37eca"></arcgis-map>
After panning the map:
<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.
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.
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
<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.
<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_
, and then set set
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
{
"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
// 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 esri
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 esri
object in AMD applications.
<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 esri
object in ESM applications.
Web maps hosted on a different portal can be initialized before being passed to the arcgis-map
component:
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.
<html lang="fr"></html>
Setting the direction
You only need to do this for Arabic and Hebrew.
<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.
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.
<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>
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.
<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