Module lifecycle events
Module lifecycle events let you react to internal state changes within a map module — independent of any user interaction. Two event types are available:
config-change— fired whenever the module's configuration is mutated (by any setter orapplyConfigcall).shown-features— fired by modules that have ashowmethod, immediately after new features are rendered on the map.
Both use the same subscription model: events.on(type, handler) returns an unsubscribe function.
config-change
Every module emits config-change when its configuration is updated, regardless of how the change was triggered. This is useful for keeping external UI in sync with module state without coupling UI logic to individual setters.
import { TrafficFlowModule } from '@tomtom-org/maps-sdk/map';
const trafficFlow = await TrafficFlowModule.get(map, { visible: false });
const unsub = trafficFlow.events.on('config-change', (config) => {
console.log('TrafficFlow config updated:', config);
// config reflects the module's full current configuration
});
// Each of these triggers a config-change event:
trafficFlow.setVisible(true);
trafficFlow.applyConfig({ visible: false });
What triggers config-change
Any method that mutates the module's configuration fires the event. Common examples:
| Method | Module |
|---|---|
setVisible(visible) |
All modules |
applyConfig(config) |
All modules |
updateConfig(partial) |
All modules |
resetConfig() |
All modules |
setKnob(module, catalogue, id, value) |
Every module with a knob catalogue |
setPalette, setColorStops, setHeight, setFilters |
TrafficAreaAnalyticsModule |
setVisible(visible, { layerGroups }) |
BaseMapModule |
The received config argument reflects the module's complete current configuration after the change.
Practical example: syncing a toggle button
import { TerrainModule } from '@tomtom-org/maps-sdk/map';
const terrain = await TerrainModule.get(map, { hillshade: false });
const toggle = document.querySelector('#hillshade-toggle') as HTMLInputElement;
terrain.events.on('config-change', (config) => {
// Keep the toggle in sync regardless of who changed visibility
toggle.checked = config?.hillshade ?? false;
});
toggle.addEventListener('change', () => terrain.setHillshadeVisible(toggle.checked));
shown-features
The shown-features event fires immediately after a module renders new data on the map. It is only available on modules that have an explicit show method.
import { PlacesModule } from '@tomtom-org/maps-sdk/map';
import { discoverPlaces } from '@tomtom-org/maps-sdk/services';
const places = await PlacesModule.create(map);
const unsub = places.events.on('shown-features', (features) => {
// A module reports every one of its show operations here, and the payload says which ran.
if ('places' in features) {
updateResultsPanel(features.places);
} else {
updateConnectionsPanel(features.connections);
}
});
const results = await discoverPlaces({ query: 'coffee' });
await places.show(results); // { places: … }
await places.showConnections([]); // { connections: … }
Which modules support shown-features
A module emits one shown-features stream covering all of its show operations, and the payload
says which one ran:
| Module | Triggered by | Feature type |
|---|---|---|
PlacesModule |
show(places) / showConnections(connections) |
{ places } or { connections } |
GeometriesModule |
show(features) |
PolygonFeatures |
RoutingModule |
showRoutes(routes) / showWaypoints(waypoints) |
{ routes } or { waypoints } |
CustomGeoJSONModule |
show(data, sourceName) |
{ sourceName, data } |
TrafficIncidentDetailsModule |
show(result) |
TrafficIncidentDetails |
TrafficAreaAnalyticsModule |
show(data) |
TrafficAreaAnalytics |
Modules that only control existing map data — TrafficFlowModule, TrafficIncidentsModule, TerrainModule, BaseMapModule, POIsModule — have no show, and events.on('shown-features', …) does not compile on them.
Practical example: fit map to shown results
import { GeometriesModule } from '@tomtom-org/maps-sdk/map';
import { bboxFromGeoJSON } from '@tomtom-org/maps-sdk/core';
const geometries = await GeometriesModule.create(map);
geometries.events.on('shown-features', (features) => {
const bbox = bboxFromGeoJSON(features);
if (bbox) {
map.mapLibreMap.fitBounds(bbox, { padding: 40 });
}
});
Cleanup
Unsubscribe — remove a single handler
Each events.on() call returns an unsubscribe function. Call it to stop receiving events from that specific handler without affecting any others:
const unsubA = places.events.on('config-change', handlerA);
const unsubB = places.events.on('config-change', handlerB);
unsubA(); // removes only handlerA — handlerB keeps firing
off() — remove all handlers for a type
events.off(type) clears every handler registered for that event type in one call. Useful during component teardown when you don't want to track individual unsubscribes:
// Clear all config-change listeners at once
trafficFlow.events.off('config-change');
// Clear all shown-features listeners at once
places.events.off('shown-features');
off accepts all event types — user interaction types (click, hover, etc.) and module lifecycle types (config-change, shown-features) — so the same teardown pattern works uniformly:
// Full cleanup for a component that registered multiple event types
function onUnmount() {
places.events.off('click');
places.events.off('hover');
places.events.off('config-change');
places.events.off('shown-features');
}
RoutingModule — lifecycle events alongside named scopes
RoutingModule draws several parts of a route, so it exposes a named scope for each. Lifecycle events stay on the module itself, under the same events.on() used everywhere else:
import { RoutingModule } from '@tomtom-org/maps-sdk/map';
const routing = await RoutingModule.create(map);
// Module lifecycle events
const unsubConfig = routing.events.on('config-change', (config) => {
console.log('Routing config changed:', config);
});
const unsubShown = routing.events.on('shown-features', (features) => {
if ('routes' in features) {
console.log('Routes shown:', features.routes);
} else {
console.log('Waypoints shown:', features.waypoints);
}
});
// User interaction events — module-wide, or through a named scope
routing.events.mainLines.on('click', (route) => { /* ... */ });
routing.events.waypoints.on('hover', (waypoint) => { /* ... */ });
Related guides
- Events Overview — All three event categories at a glance
- User Interaction Events — Click, hover, long-hover, and contextmenu events
- Map Styles — React to style transitions with
addStyleChangeHandler - Map Modules — Module initialization and configuration