Skip to Content
ExamplesData Loading - Places and Subplaces

Data Loading - Places and Subplaces

This guide explains how to load and manage places and subplaces data with the MapVX Web SDK.

Available Data Types

1. Available Places

Main places of an institution that are available for navigation.

2. Subplaces

Specific places within a parent place (building, floor, zone, etc.).

Data Loading Methods

Load Available Places

import { initializeSDK } from "@mapvx/web-js" async function loadAvailablePlaces() { const sdk = initializeSDK("your-api-key", { lang: "en" }) try { // Load available places from an institution const places = await sdk.getAvailablePlaces() console.log("Places found:", places.length) places.forEach((place) => { console.log(`- ${place.title} (${place.mapvxId})`) console.log(` Coordinates: ${place.position.lat}, ${place.position.lng}`) console.log(` Description: ${place.description || "N/A"}`) }) return places } catch (error) { console.error("Error loading places:", error) throw error } }

Load Subplaces

async function loadSubplaces(parentPlaceId: string) { const sdk = initializeSDK("your-api-key", { lang: "en" }) try { // Load subplaces from a specific parent place const subplaces = await sdk.getSubPlaces(parentPlaceId) console.log(`Subplaces of ${parentPlaceId}:`, subplaces.length) subplaces.forEach((subplace) => { console.log(`- ${subplace.title}`) console.log(` ID: ${subplace.mapvxId}`) console.log(` Floor: ${subplace.floor || "N/A"}`) console.log(` Category: ${subplace.category || "N/A"}`) }) return subplaces } catch (error) { console.error("Error loading subplaces:", error) throw error } }

Practical Integration Examples

Example 1: Dynamic Places Selector

class PlaceSelector { private sdk: MapVXSDK private selectElement: HTMLSelectElement constructor(selectElement: HTMLSelectElement) { this.selectElement = selectElement } async initialize(institutionId: string) { this.sdk = initializeSDK("your-api-key", { lang: "en" }) await this.loadPlacesIntoSelector(institutionId) } async loadPlacesIntoSelector(institutionId: string) { try { // Clear selector this.selectElement.innerHTML = '<option value="">Select a place...</option>' // Load places const places = await this.sdk.getAvailablePlaces() // Add options to selector places.forEach((place) => { const option = document.createElement("option") option.value = place.mapvxId option.textContent = place.title || place.mapvxId this.selectElement.appendChild(option) }) console.log(`${places.length} places loaded into selector`) } catch (error) { console.error("Error loading places:", error) this.selectElement.innerHTML = '<option value="">Error loading places</option>' } } async loadSubplacesForParent(parentPlaceId: string) { try { const subplaces = await this.sdk.getSubPlaces(parentPlaceId) // Clear and load subplaces this.selectElement.innerHTML = '<option value="">Select a subplace...</option>' subplaces.forEach((subplace) => { const option = document.createElement("option") option.value = subplace.mapvxId option.textContent = `${subplace.title} ${subplace.floor ? `(Floor ${subplace.floor})` : ""}` this.selectElement.appendChild(option) }) console.log(`${subplaces.length} subplaces loaded`) } catch (error) { console.error("Error loading subplaces:", error) } } } // Usage const placeSelector = new PlaceSelector(document.getElementById("placeSelect") as HTMLSelectElement) placeSelector.initialize("your-institution-id")

Example 2: Map with Conditional Initialization

class ConditionalMapLoader { private sdk: MapVXSDK private map: MapVXMap | null = null async initializeWithParentPlace(parentPlaceId: string, institutionId: string) { this.sdk = initializeSDK("your-api-key", { lang: "en" }) const mapContainer = document.getElementById("mapContainer") as HTMLElement try { // Initialize map with specific parent place this.map = await this.sdk.createMap(mapContainer, { parentPlaceId, institutionId, }) // Load subplaces from parent place const subplaces = await this.sdk.getSubPlaces(parentPlaceId) console.log(`Map created with ${subplaces.length} available subplaces`) return { map: this.map, places: subplaces } } catch (error) { console.error("Error with parent place, trying without parent place...") return await this.initializeWithoutParentPlace(institutionId) } } async initializeWithoutParentPlace(institutionId: string) { const mapContainer = document.getElementById("mapContainer") as HTMLElement try { // Initialize map without specific parent place this.map = await this.sdk.createMap(mapContainer, { institutionId }) // Load general available places const places = await this.sdk.getAvailablePlaces() console.log(`Map created with ${places.length} available places`) return { map: this.map, places: places } } catch (error) { console.error("Error initializing map:", error) throw error } } async smartInitialize(institutionId: string, preferredParentId?: string) { if (preferredParentId) { try { return await this.initializeWithParentPlace(preferredParentId, institutionId) } catch (error) { console.warn("Parent place not available, using general configuration") } } return await this.initializeWithoutParentPlace(institutionId) } } // Usage const mapLoader = new ConditionalMapLoader() // Try with preferred parent place, fallback to general configuration mapLoader .smartInitialize("institution-id", "preferred-parent-id") .then(({ map, places }) => { console.log("Map initialized successfully") console.log(`${places.length} places available`) }) .catch((error) => { console.error("Fatal error:", error) })

Example 3: Places Search and Filtering

class PlaceSearchManager { private allPlaces: any[] = [] private filteredPlaces: any[] = [] async loadAndIndexPlaces(institutionId: string, parentPlaceId?: string) { const sdk = initializeSDK("your-api-key", { lang: "en" }) try { if (parentPlaceId) { // Load subplaces if there's a parent place this.allPlaces = await sdk.getSubPlaces(parentPlaceId) } else { // Load general available places this.allPlaces = await sdk.getAvailablePlaces() } this.filteredPlaces = [...this.allPlaces] console.log(`${this.allPlaces.length} places loaded and indexed`) return this.allPlaces } catch (error) { console.error("Error loading places:", error) throw error } } searchPlaces(query: string): any[] { if (!query.trim()) { this.filteredPlaces = [...this.allPlaces] return this.filteredPlaces } const searchTerm = query.toLowerCase().trim() this.filteredPlaces = this.allPlaces.filter((place) => { const title = (place.title || "").toLowerCase() const description = (place.description || "").toLowerCase() const category = (place.category || "").toLowerCase() return ( title.includes(searchTerm) || description.includes(searchTerm) || category.includes(searchTerm) ) }) console.log(`Search "${query}": ${this.filteredPlaces.length} results`) return this.filteredPlaces } filterByCategory(category: string): any[] { if (!category) { this.filteredPlaces = [...this.allPlaces] return this.filteredPlaces } this.filteredPlaces = this.allPlaces.filter((place) => place.category === category) console.log(`Category filter "${category}": ${this.filteredPlaces.length} results`) return this.filteredPlaces } getUniqueCategories(): string[] { const categories = this.allPlaces .map((place) => place.category) .filter((category) => category) .filter((category, index, array) => array.indexOf(category) === index) return categories.sort() } } // Usage with search interface const searchManager = new PlaceSearchManager() const searchInput = document.getElementById("searchInput") as HTMLInputElement const categorySelect = document.getElementById("categorySelect") as HTMLSelectElement const resultsList = document.getElementById("resultsList") as HTMLElement // Initialize searchManager.loadAndIndexPlaces("institution-id", "optional-parent-id").then(() => { // Populate category filter const categories = searchManager.getUniqueCategories() categories.forEach((category) => { const option = document.createElement("option") option.value = category option.textContent = category categorySelect.appendChild(option) }) }) // Search functionality searchInput.addEventListener("input", (e) => { const query = (e.target as HTMLInputElement).value const results = searchManager.searchPlaces(query) displayResults(results) }) // Category filter categorySelect.addEventListener("change", (e) => { const category = (e.target as HTMLSelectElement).value const results = searchManager.filterByCategory(category) displayResults(results) }) function displayResults(places: any[]) { resultsList.innerHTML = places .map( (place) => ` <div class="place-item" data-id="${place.mapvxId}"> <h3>${place.title}</h3> <p>${place.description || "No description"}</p> <span class="category">${place.category || "No category"}</span> </div> ` ) .join("") }

Place Object Properties

Typical structure of a place

interface MVXPlace { mapvxId: string // Unique place ID title?: string // Place name description?: string // Description position: { // Coordinates lat: number lng: number } category?: string // Place category floor?: string | number // Floor (for subplaces) parentPlaceId?: string // Parent place ID institutionId?: string // Institution ID metadata?: { // Additional data [key: string]: any } }

Common Error Handling

async function robustDataLoading(institutionId: string, parentPlaceId?: string) { try { const sdk = initializeSDK("your-api-key", { lang: "en" }) let places: any[] = [] if (parentPlaceId) { try { places = await sdk.getSubPlaces(parentPlaceId) console.log(`Subplaces loaded: ${places.length}`) } catch (subplaceError) { console.warn("Error loading subplaces, trying general places:", subplaceError) places = await sdk.getAvailablePlaces() console.log(`General places loaded: ${places.length}`) } } else { places = await sdk.getAvailablePlaces() console.log(`Available places loaded: ${places.length}`) } if (places.length === 0) { console.warn("No places found to display") } return places } catch (error) { console.error("Fatal error loading data:", error) if (error.message.includes("unauthorized")) { throw new Error("Invalid API key or no permissions") } else if (error.message.includes("not found")) { throw new Error("Institution or place not found") } else { throw new Error("Connection error or service unavailable") } } }

Best Practices

  1. Enable Persistent Caching: Use the SDK’s built-in cache system for better performance
  2. Loading States: Show loading indicators while fetching data
  3. Fallback Logic: Have backup logic if subplace loading fails
  4. Error Boundaries: Handle network and permission errors appropriately
  5. Lazy Loading: Load data on demand when possible

Caching Best Practices

The SDK includes a built-in caching system that can significantly improve performance. Here are recommendations for optimal cache configuration:

Enabling Persistent Cache

For applications where users frequently return (like kiosks or directories), enable persistent caching:

const sdk = initializeSDK("your-api-key", { lang: "en", cache: { persistent: true, // Data survives page reloads }, })

Optimizing Cache for Your Use Case

Different applications have different caching needs:

// For high-traffic directory applications const sdk = initializeSDK("your-api-key", { lang: "en", cache: { persistent: true, maxStorageBytes: 10 * 1024 * 1024, // 10MB for large venues configs: { places: { maxItems: 2000, // Large venue with many places ttlMs: 60 * 60 * 1000, // 1 hour - places don't change often }, subPlaces: { maxItems: 500, ttlMs: 30 * 60 * 1000, // 30 minutes }, routes: { maxItems: 300, // More routes for busy applications ttlMs: 15 * 60 * 1000, // 15 minutes - routes are more dynamic }, configurations: { maxItems: 20, ttlMs: 2 * 60 * 60 * 1000, // 2 hours - configurations rarely change }, }, }, })

Using Cached Data

The SDK automatically uses cached data when available. You can also access cached places directly:

// Get places that are already in cache (no network request) const cachedPlaces = sdk.getCachedPlaces(["place-id-1", "place-id-2", "place-id-3"]) console.log(`Found ${cachedPlaces.length} places in cache`)

Cache Invalidation

When you need fresh data, clear the routes cache:

// Clear cached routes when you know data has changed sdk.cleanRoutesCache() // Then fetch fresh route data const freshRoute = await sdk.getRoute(routeConfig)

Example: Data Loading with Cache Strategy

class OptimizedDataLoader { private sdk: MapVXSDK async initialize() { this.sdk = initializeSDK("your-api-key", { lang: "en", cache: { persistent: true, configs: { places: { maxItems: 1000, ttlMs: 60 * 60 * 1000 }, }, }, }) } async loadPlaces(institutionId: string): Promise<MVXPlace[]> { try { // SDK automatically uses cache if available const places = await this.sdk.getAvailablePlaces() console.log(`Loaded ${places.length} places`) return places } catch (error) { console.error("Error loading places:", error) throw error } } // Use cached data for quick lookups getPlaceFromCache(placeIds: string[]): MVXPlace[] { return this.sdk.getCachedPlaces(placeIds) } }
Last updated on