Create a Search Experience

Goal: This guide will show you how to add a search input field to your map application, allowing users to find locations within your venue. Search results will be displayed in a list and highlighted on the map.

SDK Concepts Introduced:

  • Using mapsindoors.services.LocationsService.getLocations() to fetch locations based on a query.

  • Interacting with the map based on search results:

    • Highlighting multiple locations: mapsIndoorsInstance.highlight().

    • Setting the floor: mapsIndoorsInstance.setFloor().

    • Selecting a specific location: mapsIndoorsInstance.selectLocation().

  • Clearing previous highlights and selections: mapsIndoorsInstance.highlight() (with no arguments) and mapsIndoorsInstance.deselectLocation().

  • Getting current venue information: mapsIndoorsInstance.getVenue().

Prerequisites

  • Completion of Step 1: Display a Map.

  • Your MapsIndoors API Key and Google Maps JavaScript API Key should be correctly set up as per Step 1. We will continue using the demo API key 02c329e6777d431a88480a09 and venue ID dfea941bb3694e728df92d3d for this example.

The Code

This guide details the modifications to HTML, CSS, and JavaScript needed to add a search input field, display search results, and dynamically interact with the map based on user searches.

Update index.html

Open your index.html file. The primary structural change to your HTML is the introduction of a dedicated search panel. This panel will house the input field where users type their search queries and an unordered list where the corresponding search results will appear.

Explanation of index.html updates:

  • A new div element with the class panel is added. This div serves as the main container for all search-related UI elements.

  • Inside the panel, another div with the id search-ui and the class flex-column is introduced to arrange the search input and results list vertically.

  • An <input> element with id="search-input" is the text field for user search queries.

  • An <ul> (unordered list) element with id="search-results" will be dynamically populated with locations matching the user's query.

Update style.css

Modify your style.css file to incorporate styles for the newly added search panel and its contents. These styles are crucial for ensuring the search interface is user-friendly, visually appealing, and correctly positioned over the map without obstructing it entirely.

Explanation of style.css updates:

  • .panel: Styles the search panel to float over the map in the top-left corner, with a white background, padding, rounded corners, and a shadow for a modern look. max-height and overflow-y: auto ensure it's scrollable if results are numerous.

  • .flex-column: A utility class using Flexbox to stack child elements (search input, results list) vertically with a small gap.

  • .hidden: A utility class to hide elements (display: none;), used initially for the search results list.

  • #search-input: Styles the search input field with padding, border, and font size for readability.

  • #search-results: Styles the unordered list for search results, removing default list styling.

  • #search-results li: Styles individual list items with padding, a bottom border for separation, and a pointer cursor to indicate clickability.

  • #search-results li:last-child: Removes the bottom border from the last list item.

  • #search-results li:hover: Provides a hover effect for list items for better user feedback.

Update script.js

The script.js file sees the most significant changes as it houses the logic for the search functionality.

Explanation of script.js updates:

  • DOM Element References: searchInputElement and searchResultsElement get references to the HTML input field and the unordered list for displaying results, respectively.

  • Initial State: The searchResultsElement is hidden by default using the .hidden CSS class.

  • Event Listener: An input event listener is attached to searchInputElement. This calls the onSearch function each time the user types into the search field.

  • onSearch() Function: This is the core of the search logic:

    • It retrieves the current query from the input field and gets the currentVenue using mapsIndoorsInstance.getVenue(). For more details on venue information, see the getVenue() reference.

    • It clears any existing highlights from the map using mapsIndoorsInstance.highlight() (called without arguments). See its API documentation for more on clearing highlights.

    • It deselects any currently selected location using mapsIndoorsInstance.deselectLocation(). Refer to its API documentation for deselection behavior.

    • If the query length is less than 3 characters, it hides the searchResultsElement and exits to prevent overly broad or empty searches.

    • It prepares searchParameters with the q (query) and scopes the search to the currentVenue.name. For a comprehensive list of search options, check out the LocationsService.getLocations() documentation

    • It calls mapsindoors.services.LocationsService.getLocations(searchParameters) to fetch locations. This asynchronous method returns a Promise.

    • .then(locations => { ... }): This block handles the successful response from the LocationsService. locations is an array of objects, where each object conforms to the Location interface.

      • It clears previous search results by setting searchResultsElement.innerHTML = null.

      • If no locations are found, it displays a "No results found" message in the list.

      • Otherwise, it iterates through each location object:

        • Creates an <li> element.

        • Sets its innerHTML to location.properties.name. The properties object on an object conforming to the Location interface contains various details about the location. For more information, see the Location documentation.

        • Stores location.id in listElement.dataset.locationId for potential future use.

        • Adds a click event listener to the list item. When clicked:

          • mapsIndoorsInstance.goTo(location): Pans and zooms the map to the clicked location. For more details on goTo(), see its reference.

          • mapsIndoorsInstance.setFloor(location.properties.floor): Changes the map to the location's floor. To understand floor management, check the setFloor() documentation.

          • mapsIndoorsInstance.selectLocation(location): Selects and highlights this specific location on the map. For further information, refer to the selectLocation() API documentation.

        • Appends the new list item to searchResultsElement.

        • Collects all location.ids into locationIdsToHighlight.

      • Makes the searchResultsElement visible by removing the .hidden class.

      • Calls mapsIndoorsInstance.highlight(locationIdsToHighlight) to highlight all found locations on the map simultaneously. The highlight() method accepts an array of location IDs. See its API documentation for details on batch highlighting.

    • .catch(error => { ... }): Handles potential errors during the search request, logging them to the console and displaying an error message in the list.

  • The handleLocationClick function is now used for both map clicks and search result clicks, ensuring consistent behavior and code reuse.

  • When a user clicks a search result or a POI on the map, the map will center on that location, switch to the correct floor, and select the location.

  • This pattern will be reused and expanded in later steps.

Expected Outcome

After implementing these changes:

  • A search panel will be visible in the top-left corner of your map.

  • Typing 3 or more characters into the search input will trigger a search.

  • Matching locations will appear as a clickable list below the search input.

  • All matching locations will be highlighted on the map.

  • Clicking a location in the list will:

    • Pan and zoom the map to that location.

    • Switch to the correct floor if necessary.

    • Select and distinctively highlight that specific location on the map.

Troubleshooting

  • Search not working / No results:

    • Check the browser's developer console (F12) for errors.

    • Ensure your MapsIndoors API Key (02c329e6777d431a88480a09 for demo) is correct and the MapsIndoors SDK is loaded.

    • Verify YOUR_GOOGLE_MAPS_API_KEY is correct.

    • Confirm the venue ID (dfea941bb3694e728df92d3d for demo) is valid and the venue has searchable locations.

    • Make sure the onSearch function is being called (e.g., add a console.log at the beginning of onSearch).

  • Results list doesn't appear or looks wrong:

    • Check CSS for the .panel, #search-results, and li elements. Ensure the .hidden class is being correctly added/removed.

  • Map interactions (goTo, highlight, selectLocation) not working:

    • Verify mapsIndoorsInstance is correctly initialized.

    • Ensure the location objects passed to these methods are valid objects conforming to the Location interface.

    • Check for console errors when clicking a search result.

Next Steps

You've now successfully added a powerful search feature to your indoor map! Users can easily find their way to specific points of interest.

Next, learn how to display detailed information about a selected location:

Last updated

Was this helpful?