Learn how to perform a text-based search to find places within a bounding box.
The ArcGIS Places service
In this tutorial, use ArcGIS REST JS to perform a bounding box search based on the visible extent on the map and return details about each place. You also use Calcite components to create a basic search interface.
Prerequisites
An ArcGIS Location Platform account.
Steps
Get the starter app
Select a type of authentication and follow the steps to create a new app.
Choose API key authentication if you:
- Want the easiest way to get started.
- Want to build public applications
A public application is an application that allows anonymous access without requiring users to sign in with an ArcGIS account. It supports API key or app authentication. that access ArcGIS Location ServicesArcGIS Location Services, also referred to as Location Services, are services hosted by Esri that provide geospatial functionality for developing mapping applications. They include the ArcGIS Basemap Styles service, ArcGIS Static Basemap Tiles service, ArcGIS Places service, ArcGIS Geocoding service, ArcGIS Routing service, ArcGIS GeoEnrichment service, and ArcGIS Elevation service. An ArcGIS Location Platform or ArcGIS Online account is required to use the services. and secure itemsAn item, also known as a content item, is a resource stored in a portal such as a web map, hosted layer, style, script tool, file, or notebook. . - Have an ArcGIS Location Platform or ArcGIS Online account.
Choose user authentication if you:
- Want to build private applications.
- Require application users to sign in with their own ArcGIS account
An ArcGIS account is an identity with a user type and set of privileges that can access specific ArcGIS products, tools, APIs, services, and resources. The main account types that can be used for development are an ArcGIS Location Platform account, ArcGIS Online account, and ArcGIS Enterprise account. ArcGIS Location Platform and ArcGIS Online accounts are also associated with a subscription. and access resources their behalf. - Have an ArcGIS Online account.
To learn more about both types of authentication, go to Authentication.
Set up authentication
Set developer credentials
Use the API key or OAuth developer credentials
Add script references
Reference the ArcGIS REST JS request and places packages to perform a bounding box search operation. You also reference the Calcite library to create the user interface.
-
Reference the
routingandrequestpackages from ArcGIS REST JS.Use dark colors for code blocks <!-- Load Leaflet from CDN --> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" crossorigin=""> <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" crossorigin=""></script> <!-- Load Esri Leaflet from CDN --> <script src="https://unpkg.com/esri-leaflet@3.0.19/dist/esri-leaflet.js"></script> <script src="https://unpkg.com/esri-leaflet-vector@4.3.2/dist/esri-leaflet-vector.js"></script> <!-- ArcGIS REST JS: request and places --> <script src="https://unpkg.com/@esri/arcgis-rest-request@4/dist/bundled/request.umd.js"></script> <script src="https://unpkg.com/@esri/arcgis-rest-places@1/dist/bundled/places.umd.js"></script> -
Reference the Calcite Design System library.
Use dark colors for code blocks <!-- Load Leaflet from CDN --> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" crossorigin=""> <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" crossorigin=""></script> <!-- Load Esri Leaflet from CDN --> <script src="https://unpkg.com/esri-leaflet@3.0.19/dist/esri-leaflet.js"></script> <script src="https://unpkg.com/esri-leaflet-vector@4.3.2/dist/esri-leaflet-vector.js"></script> <!-- Calcite components --> <script type="module" src="https://js.arcgis.com/calcite-components/3.3.3/calcite.esm.js"></script> <link rel="stylesheet" href="https://js.arcgis.com/calcite-components/3.3.3/calcite.css"> <!-- ArcGIS REST JS: request and places --> <script src="https://unpkg.com/@esri/arcgis-rest-request@4/dist/bundled/request.umd.js"></script> <script src="https://unpkg.com/@esri/arcgis-rest-places@1/dist/bundled/places.umd.js"></script> -
Create a REST JS
Apiusing your access token.Key Manager Use dark colors for code blocks const authentication = arcgisRest.ApiKeyManager.fromKey(accessToken);
Update interface
-
Change the map's viewpoint to
[47.62737, -122.32116]with a zoom of14to focus on Seattle, Washington.Use dark colors for code blocks Copy const map = L.map("map", { minZoom: 13 }).setView([47.62737, -122.32116], 14); //Latitude, longitude -
Inside
<body, copy and paste the following HTML to create a basic search interface.> Use dark colors for code blocks <div id="place-control"> <div class="search"> <calcite-input type="text" id="search-input" placeholder="Type in a place name or category"> <calcite-button kind="inverse" icon-start="search" id="search-button" type="submit" slot="action" ></calcite-button> </calcite-input> </div> </div> <div id="map"></div> -
Add styling for the new elements and add a
z-indexof1to the map<divelement.> Use dark colors for code blocks body { margin: 0; padding: 0; } #map { position: absolute; top: 0; bottom: 0; right: 0; left: 0; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; z-index:1; } #place-control { position:absolute; top:15px; left:15px; display:flex; flex-direction: row; z-index: 2; } .search { margin-right:15px; } #search-input { width:270px; } .category-button { margin:auto 5px; } -
Create a set of dynamic buttons for place categories (e.g.,
Restaurants,Hotels,Museums) usingcalcite-buttonelements. Then, adjust the map's zoom control position to bottom right.Use dark colors for code blocks const control = document.getElementById("place-control"); const input = document.getElementById("search-input"); const placeKeywords = ["Restaurants", "Hotels", "Museums", "ATMs", "Breweries"]; placeKeywords.forEach((category) => { const categoryButton = L.DomUtil.create("calcite-button", "category-button"); categoryButton.setAttribute("round", true); categoryButton.setAttribute("scale", "s"); categoryButton.setAttribute("kind", "inverse"); categoryButton.innerHTML = category; categoryButton.id = category; control.appendChild(categoryButton); }); map.zoomControl.setPosition("bottomright");
Add event listeners
The provided for this tutorial includes a basic user interface with a text input and category buttons. Add event listeners to this interface to make requests to the ArcGIS Places service on when they are clicked.
-
Create a
showfunction to make requests to the Places service.Places Use dark colors for code blocks function showPlaces(text) { }; -
Add an event listener to the search button that calls
showon click.Places Use dark colors for code blocks const control = document.getElementById("place-control"); const input = document.getElementById("search-input"); const placeKeywords = ["Restaurants", "Hotels", "Museums", "ATMs", "Breweries"]; document.getElementById("search-button").addEventListener("click", () => { showPlaces(input.value); }); placeKeywords.forEach((category) => { const categoryButton = L.DomUtil.create("calcite-button", "category-button"); categoryButton.setAttribute("round", true); categoryButton.setAttribute("scale", "s"); categoryButton.setAttribute("kind", "inverse"); categoryButton.innerHTML = category; categoryButton.id = category; control.appendChild(categoryButton); }); map.zoomControl.setPosition("bottomright"); -
Add an event listener to each category button that calls
showon click.Places Use dark colors for code blocks placeKeywords.forEach((category) => { const categoryButton = L.DomUtil.create("calcite-button", "category-button"); categoryButton.setAttribute("round", true); categoryButton.setAttribute("scale", "s"); categoryButton.setAttribute("kind", "inverse"); categoryButton.innerHTML = category; categoryButton.id = category; control.appendChild(categoryButton); categoryButton.addEventListener("click", () => { input.value = category; showPlaces(category); }); }); map.zoomControl.setPosition("bottomright");
Find places in the map bounds
-
Calculate the current visible extent of the Leaflet map with
map.get. Access the top right and bottom left corners.Bounds() Use dark colors for code blocks function showPlaces(text) { const bounds = map.getBounds(); const topRight = bounds.getNorthEast(); const bottomLeft = bounds.getSouthWest(); }; -
Use the ArcGIS REST JS
findoperation to make a request to the Places service. Set thePlaces Within Extent searchparameter to the input text and pass the current map bounding box to theText xmin,xmax,ymin, andymaxparameters.Use dark colors for code blocks function showPlaces(text) { const bounds = map.getBounds(); const topRight = bounds.getNorthEast(); const bottomLeft = bounds.getSouthWest(); arcgisRest.findPlacesWithinExtent({ xmin: bottomLeft.lng, ymin: bottomLeft.lat, xmax: topRight.lng, ymax: topRight.lat, searchText: text, authentication }) };
Display results
The response from the Places service will contain a list of place results. Each result will include the x/y coordinates, name, category, and unique ID associated with a place.
-
Add a new
Layerto your map to display service results. When a new places request is made, clear theGroup Layer.Group Use dark colors for code blocks const layerGroup = L.layerGroup().addTo(map); function showPlaces(text) { layerGroup.clearLayers(); -
Access the service results. For each result, add a Leaflet
Markerto your map.Use dark colors for code blocks function showPlaces(text) { layerGroup.clearLayers(); const bounds = map.getBounds(); const topRight = bounds.getNorthEast(); const bottomLeft = bounds.getSouthWest(); arcgisRest.findPlacesWithinExtent({ xmin: bottomLeft.lng, ymin: bottomLeft.lat, xmax: topRight.lng, ymax: topRight.lat, searchText: text, authentication }) .then((response) => { response.results.forEach((result) => { const marker = L.marker([result.location.y, result.location.x]) .addTo(layerGroup); }); }); }; -
Run the app. When you click a category button or search for a phrase, the map should display a set of points representing place results.
Display a popup
To view more information about each place result, bind a popup to each marker that displays more information about the place.
-
Use
bindto bind a popup to each result marker. Create the popup contents dynamically using a new function. The current Leaflet marker is automatically passed as the first function parameter.Popup Use dark colors for code blocks .then((response) => { response.results.forEach((result) => { const marker = L.marker([result.location.y, result.location.x]) .addTo(layerGroup); marker.bindPopup(getDetails, { minWidth: 200 }); }); }); }; function getDetails(place) { const popup = document.createElement("div"); return popup; }; -
Set the
idof each marker to the uniqueplaceassociated with the POI.Id Use dark colors for code blocks .then((response) => { response.results.forEach((result) => { const marker = L.marker([result.location.y, result.location.x]) .addTo(layerGroup); marker.id = result.placeId; marker.bindPopup(getDetails, { minWidth: 200 }); }); });
Get place address and phone number
You can access more information about a place using the unique place associated with it. Perform a subsequent request to the Places service to get the street address and phone number of a clicked POI.
-
Use the ArcGIS REST JS
getfunction to get detailed information about a specific place. Pass thePlace Details placeassociated with the current marker, and set theId requestedparameter to return theFields streetandAddress telephoneproperties.Use dark colors for code blocks function getDetails(place) { const popup = document.createElement("div"); arcgisRest.getPlaceDetails(({ placeId: place.id, authentication, requestedFields: ["name", "address:streetAddress", "contactInfo:telephone"] })) return popup; }; -
Access the service response. Display the results in your popup if they are available.
Use dark colors for code blocks function getDetails(place) { const popup = document.createElement("div"); arcgisRest.getPlaceDetails(({ placeId: place.id, authentication, requestedFields: ["name", "address:streetAddress", "contactInfo:telephone"] })) .then((result) => { let popupContents = `<b>${result.placeDetails.name}</b><br>`; if (result.placeDetails.address.streetAddress) popupContents += `${result.placeDetails.address.streetAddress}<br>`; if (result.placeDetails.contactInfo.telephone) popupContents += `${result.placeDetails.contactInfo.telephone}`; popup.innerHTML = popupContents; }); return popup; };
Run the app
Run the app.
The app should display a map with a search control. Upon clicking a button or entering a phrase, place results should appear on the map. Clicking a result will submit another service request to get the place address and phone number.What's next?
Learn how to use additional location services in these tutorials:


