Watch for changes in web components
Watching for changes on properties or attributes on a JavaScript Maps SDK component is essential for detecting and implementing custom responses to those changes in your application. You can watch for changes using a component's events, a mutation observer or a proxy. The Watch for changes in components sample demonstrates some of these concepts.
Using component events
Components may emit information about changes to their state as events.
The changes can be initiated by internal changes, user interaction or when setting properties or attributes.
Listen for events by using the add
method.
The event's payload contains information about the change 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("arcgisTriggerAction", async (event) => {
// event.detail is used here since the event type is CustomEvent<LayerListTriggerActionEvent>
// It returns data passed when initializing the event.
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail
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.
For example, to watch for view-related property changes, such as zoom
, on the arcgis-map
component, use the arcgis
event.
const mapElement = document.querySelector("arcgis-map");
mapElement.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>
// The void means that there are no details provided by the event, itself.
const { zoom } = event.target;
console.log(`The zoom is ${zoom}`);
})
The arcgis
event is particularly useful for detecting when a Map, WebMap or WebScene has been initially loaded or updated on the arcgis-map
or arcgis-scene
component.
Here are the scenarios that trigger arcgis
:
- Initial load: When the
arcgis-map
orarcgis-scene
component's map is initially set, the event will fire once the view is ready. - Updates: If the map of a map or scene component is replaced with either a
Map
,Web
, orMap Web
, the event will fire again. Changing theScene item-id
will also trigger the event, signaling that a new WebMap or WebScene has been loaded.
const map = document.querySelector("arcgis-map");
map.addEventListener("arcgisViewReadyChange", () => {
console.log(`New WebMap loaded with itemId: ${map.itemId}`);
// Perform actions based on the newly loaded WebMap
});
// Example of switching the WebMap after a delay
setTimeout(() => {
map.itemId = "new-webmap-id";
}, 3000);
The arcgis
event allows for the monitoring of property changes in non-view-based components.
For instance, in the arcgis-area-measurement-2d component, the arcgis
event can be used to track the state of the measurement process, such as when a user initiates or completes a measurement.
const areaMeasurement = document.querySelector("arcgis-area-measurement-2d");
areaMeasurement.addEventListener("arcgisPropertyChange", (e) => {
if (e.detail.name === "state") {
console.log("Measurement state:", e.target[e.detail.name]);
}
});
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.
The observer approach allows for efficient tracking of mutations over the entire DOM tree, without needing an event listener. Observers use weak references to DOM nodes, so when nodes are removed they can be garbage collected. And, you can also continue to observe disconnected DOM nodes.
Changes that are reflected on the DOM can be visibly observed in a browser's developer tools. One example is when a map is panned, the arcgis-map
component's updating
attribute will appear for a few seconds.
Before panning the map:
<arcgis-map item-id="05e015c5f0314db9a487a9b46cb37eca"></arcgis-map>
During panning the map:
<arcgis-map item-id="05e015c5f0314db9a487a9b46cb37eca" updating></arcgis-map>
In the example below, the mutation observer will fire a callback function when any of the arcgis-map
component's attributes are modified by the application or the component.
const mapElement = document.querySelector("arcgis-map");
const observer = new MutationObserver((mutations, observer) => {
for (let mutation of mutations) {
console.log(`Mutation observer: ${mutation.attributeName} changed to ${mutation.target[mutation.attributeName]}`);
}
});
// Start observing the map's attributes for changes, such as the updating property
observer.observe(mapElement, { attributeFilter: ["updating"] });
// Change the zoom level after 10 seconds
setTimeout(() => {
mapElement.zoom = 7;
}, "10000");
The References for Maps SDK components list the properties that are reflected on the DOM and can be watched with a mutation observer.
Using a proxy
A proxy is useful for observing or trapping changes your application makes programmatically to a component's properties before the component can act on them.
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 explicitly set in your code. When these changes are trapped, they are essentially intercepted and you can take any action you want before passing on the new value or modifying it in some way. You can also read more about Proxy at javascript.info.
const mapElement = 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(obj,prop,value) {
obj[prop] = value; // set property to new value
console.log(`Proxy: the ${prop} property was changed to ${value}`);
return true;
}
}
// Initialize the new proxy
let proxy = new Proxy(mapElement, handler);
// Change to a different basemap and zoom level
const changeBasemap = () => {
proxy.zoom = 7;
proxy.basemap = "streets-vector";
}
Watch for changes in the API
reactive
provides the ability to track changes in API properties with a variety of different data types and structures, such as strings, booleans, arrays, collections, and objects. The module also allows for combining properties from multiple sources. It includes the following methods: watch()
, on()
, once()
, when()
, and when
.
reactive
also provide TypeScript type checking. You can access properties, build objects or perform other calculations and it is all properly checked by the TypeScript compiler. Callback parameters are also correctly inferred from the get
function.
To see reactive
in action, you can explore these samples: