Skip to content

MapInstance — module-level vs instance-level API

init() returns a MapInstance handle representing the embedded map. Most lifecycle and command methods are also accessible at the module level (mapsted.maps.*) because the API is designed around a single map per page. Both surfaces exist intentionally — this page explains why and when to prefer each.

What MapInstance is

ts
import * as maps from '@mapsted/maps-js-api';

const map = await maps.init({
  element: '#map-container',
  propertyId: 603,
  mapsDomain: 'https://maps.mapsted.com',
});

map is the MapInstance returned by init(). It exposes:

MethodPurpose
destroy()Tear the iframe down and reset all state.
getState()Snapshot of current MapState (active building, floor, language, lifecycle state).
isReady()Async — resolves to true once the lifecycle is in READY state (await it).
subscribe()React-style state subscription. Distinct from event-system on().

The dual API surface

Almost every method is callable both ways:

ts
// Instance-level
await map.destroy();
const state = await map.getState();

// Module-level — equivalent
await maps.destroy();
const state = await maps.getState();

Both forms target the same singleton internally. Module-level calls are the older surface (V2/V3 ergonomic muscle memory); instance-level calls are the canonical contract returned by init().

Single-map-per-page constraint

The API is designed around a single mounted map per page. Calling init() a second time without a prior destroy() throws MAPSTED-1001. Both the module-level and instance-level handles refer to the same underlying iframe.

ts
const a = await maps.init({ element: '#map-1', propertyId: 603 /* ... */ });
await maps.init({ element: '#map-2', propertyId: 603 /* ... */ }); // throws MAPSTED-1001

To swap maps:

ts
await a.destroy();
const b = await maps.init({ element: '#map-2', propertyId: 603 /* ... */ });

When to prefer instance-level

  • TypeScript ergonomics — the typed MapInstance handle gives IDE autocomplete and lets you pass the map around as a value (e.g. into a React Context or a Redux store).
  • Multi-component composition — a top-level component owns the MapInstance from init() and child components receive it via props rather than reaching for the global.
  • Test mocking — easier to stub a typed object than a global namespace.

When to prefer module-level

  • CDN / single-script embedding — the IIFE bundle exposes window.mapsted.maps.* for legacy V2/V3 muscle memory; existing CDN snippets keep working.
  • Quick console debuggingmapsted.maps.getState() is one autocomplete hop in the browser devtools console without needing the instance reference.
  • Lifecycle calls before init()await mapsted.maps.isReady() is callable before init() resolves (it resolves to false); the instance does not exist yet.

Subscriptions: instance-level vs event system

MapInstance also exposes subscribe(), which is distinct from the event system on()/off()/once():

APIFires onUse for
instance.subscribe(handler)Any MapState field changeReact/Vue/Svelte state syncing
maps.on(eventName, handler)A specific named event firingDiscrete event reactions (selection, navigation, idle, theme)

See Event system for the event-driven API and Lifecycle for the state-machine view.