Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9253995
fix: Quality and standards improvements.
willum070 Sep 17, 2025
4f0353d
Merge branch 'main' into fix-place-ac-session
willum070 Sep 17, 2025
1af35c0
Update samples/place-autocomplete-data-session/index.ts
willum070 Sep 19, 2025
23d4276
Enhance gmp-map with additional attributes and classes
willum070 Sep 22, 2025
64ab96b
Refactor CSS selectors to use class syntax
willum070 Sep 22, 2025
b350781
Refactor autocomplete session handling and cleanup
willum070 Sep 22, 2025
e2883a6
Adds session token counter.
willum070 Sep 23, 2025
57baad0
Merge branch 'main' into fix-place-ac-session
willum070 Sep 23, 2025
738da0f
Prettier
willum070 Sep 23, 2025
d203021
Ran prettier; removed commented code
willum070 Sep 24, 2025
da33958
Ran prettier formatting
willum070 Sep 24, 2025
4effd14
Prettier Format CSS for consistency and readability
willum070 Sep 24, 2025
adb701e
Merge branch 'main' into fix-place-ac-session
willum070 Sep 25, 2025
98b82b5
Merge branch 'main' into fix-place-ac-session
willum070 Sep 25, 2025
1f27746
Review code changes
willum070 Sep 25, 2025
e3c99d6
Review changes
willum070 Sep 25, 2025
1a47e7c
Remove more id (forgot on the first pass)
willum070 Sep 26, 2025
4b0872a
Replace anchor with button for accessibility
willum070 Sep 26, 2025
af3d8b1
Add link-button styles for improved accessibility
willum070 Sep 26, 2025
fc79d31
Remove language and region from autocomplete config
willum070 Sep 26, 2025
116602a
Fixes from Will and Chris collab session
willum070 Sep 29, 2025
939fcbc
Merge branch 'main' into fix-place-ac-session
willum070 Sep 29, 2025
bba54e4
Remove refreshToken call in autocomplete setup
willum070 Sep 30, 2025
36e635b
Update samples/place-autocomplete-data-session/index.ts
willum070 Oct 1, 2025
434554c
Applied review comments
willum070 Oct 1, 2025
6248e80
Merge branch 'main' into fix-place-ac-session
willum070 Oct 1, 2025
8927b76
Refactor CSS for place button and layout styles
willum070 Oct 3, 2025
00f9c75
Merge branch 'main' into fix-place-ac-session
willum070 Oct 3, 2025
0fc1c86
Incorporated
willum070 Oct 3, 2025
1105f9a
Update styles for place-button and results
willum070 Oct 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 28 additions & 29 deletions samples/place-autocomplete-data-session/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,34 @@
-->
<!-- [START maps_place_autocomplete_data_session] -->
<html>
<head>
<title>Place Autocomplete Data API Session</title>
<head>
<title>Place Autocomplete Data API Session</title>

<link rel="stylesheet" type="text/css" href="./style.css" />
<script type="module" src="./index.js"></script>
</head>
<body>
<!-- // [START maps_place_autocomplete_data_session_html] -->
<input id="input" type="text" placeholder="Search for a place..." />
<div id="title"></div>
<ul id="results"></ul>
<img
class="powered-by-google"
src="https://storage.googleapis.com/geo-devrel-public-buckets/powered_by_google_on_white.png"
alt="Powered by Google"
/>
<!-- // [END maps_place_autocomplete_data_session_html] -->

<!--
The `defer` attribute causes the script to execute after the full HTML
document has been parsed. For non-blocking uses, avoiding race conditions,
and consistent behavior across browsers, consider loading using Promises. See
https://developers.google.com/maps/documentation/javascript/load-maps-js-api
for more information.
-->
<script
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8&callback=init&libraries=places&v=weekly"
defer
></script>
</body>
<link rel="stylesheet" type="text/css" href="./style.css" />
<script type="module" src="./index.js"></script>
<!-- prettier-ignore -->
<script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
({key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "weekly"});</script>
</head>
<body>
<!-- // [START maps_place_autocomplete_data_session_html] -->
<gmp-map center="37.7893, -122.4039" zoom="12" map-id="DEMO_MAP_ID">
<div
class="controls"
slot="control-inline-start-block-start"
>
<input
type="text"
class="input"
placeholder="Search for a place..."
autocomplete="off"
/><!-- Turn off the input's own autocomplete (not supported by all browsers).-->
<div class="token-status"></div>
<div class="title"></div>
<ol class="results"></ol>
</div>
</gmp-map>
<!-- // [END maps_place_autocomplete_data_session_html] -->
</body>
</html>
<!-- [END maps_place_autocomplete_data_session] -->
145 changes: 96 additions & 49 deletions samples/place-autocomplete-data-session/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,97 +5,144 @@
*/

// [START maps_place_autocomplete_data_session]
let titleElement;
let resultsContainerElement;
let inputElement;

const mapElement = document.querySelector('gmp-map') as google.maps.MapElement;
let innerMap: google.maps.Map;
let marker: google.maps.marker.AdvancedMarkerElement;
let titleElement = document.querySelector('.title') as HTMLElement;
let resultsContainerElement = document.querySelector('.results') as HTMLElement;
let inputElement = document.querySelector('input') as HTMLInputElement;
let tokenStatusElement = document.querySelector('.token-status') as HTMLElement;
let newestRequestId = 0;
let tokenCount = 0;

// Add an initial request body.
const request = {
// Create an initial request body.
const request: google.maps.places.AutocompleteRequest = {
input: '',
locationRestriction: { west: -122.44, north: 37.8, east: -122.39, south: 37.78 },
origin: { lat: 37.7893, lng: -122.4039 },
includedPrimaryTypes: ['restaurant'],
language: 'en-US',
region: 'us',
};

function init() {
titleElement = document.getElementById('title');
resultsContainerElement = document.getElementById('results');
inputElement = document.querySelector('input');
includedPrimaryTypes: [
'restaurant',
'cafe',
'museum',
'park',
'botanical_garden',
],
}

async function init() {
await google.maps.importLibrary('maps');
innerMap = mapElement.innerMap;
innerMap.setOptions({
mapTypeControl: false,
});

// Update request center and bounds when the map bounds change.
google.maps.event.addListener(innerMap, 'bounds_changed', async () => {
request.locationRestriction = innerMap.getBounds();
request.origin = innerMap.getCenter();
});

inputElement.addEventListener('input', makeAutocompleteRequest);
refreshToken(request);
}

async function makeAutocompleteRequest(inputEvent) {
// Reset elements and exit if an empty string is received.
if (inputEvent.target.value == '') {
titleElement.innerText = '';
// To avoid race conditions, store the request ID and compare after the request.
const requestId = ++newestRequestId;

const { AutocompleteSuggestion } = (await google.maps.importLibrary(
'places'
)) as google.maps.PlacesLibrary;

if (!inputEvent.target?.value) {
titleElement.textContent = '';
resultsContainerElement.replaceChildren();
return;
}

// Add the latest char sequence to the request.
request.input = inputEvent.target.value;

// To avoid race conditions, store the request ID and compare after the request.
const requestId = ++newestRequestId;
request.input = (inputEvent.target as HTMLInputElement).value;

// Fetch autocomplete suggestions and show them in a list.
// @ts-ignore
const { suggestions } = await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(request);
const { suggestions } =
await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);

// If the request has been superseded by a newer request, do not render the output.
if (requestId !== newestRequestId) return;

titleElement.innerText = `Query predictions for "${request.input}"`;
titleElement.innerText = `Place predictions for "${request.input}"`;

// Clear the list first.
resultsContainerElement.replaceChildren();

for (const suggestion of suggestions) {
const placePrediction = suggestion.placePrediction;

if (!placePrediction) {
continue;
}

// Create a link for the place, add an event handler to fetch the place.
const a = document.createElement('a');
a.addEventListener('click', () => {
onPlaceSelected(placePrediction!.toPlace());
// We are using a button element to take advantage of its a11y capabilities.
const placeButton = document.createElement('button');
placeButton.addEventListener('click', () => {
onPlaceSelected(placePrediction.toPlace());
});
a.innerText = placePrediction!.text.toString();
placeButton.textContent = placePrediction.text.toString();
placeButton.classList.add('place-button');

// Create a new list item element.
const li = document.createElement('li');
li.appendChild(a);
li.appendChild(placeButton);
resultsContainerElement.appendChild(li);
}
}

// Event handler for clicking on a suggested place.
async function onPlaceSelected(place) {
async function onPlaceSelected(place: google.maps.places.Place) {
const { AdvancedMarkerElement } = (await google.maps.importLibrary(
'marker'
)) as google.maps.MarkerLibrary;

await place.fetchFields({
fields: ['displayName', 'formattedAddress'],
fields: ['displayName', 'formattedAddress', 'location'],
});
const placeText = document.createTextNode(`${place.displayName}: ${place.formattedAddress}`);
resultsContainerElement.replaceChildren(placeText);
titleElement.innerText = 'Selected Place:';

resultsContainerElement.textContent = `${place.displayName}: ${place.formattedAddress}`;
titleElement.textContent = 'Selected Place:';
inputElement.value = '';
refreshToken(request);

await refreshToken();

// Remove the previous marker, if it exists.
if (marker) {
marker.remove();
}

// Create a new marker.
marker = new AdvancedMarkerElement({
map: innerMap,
position: place.location,
title: place.displayName,
})

// Center the map on the selected place.
if (place.location) {
innerMap.setCenter(place.location);
innerMap.setZoom(15);
}
}

// Helper function to refresh the session token.
function refreshToken(request) {
async function refreshToken() {
const { AutocompleteSessionToken } = (await google.maps.importLibrary(
'places'
)) as google.maps.PlacesLibrary;

// Increment the token counter.
tokenCount++;

// Create a new session token and add it to the request.
request.sessionToken = new google.maps.places.AutocompleteSessionToken();
request.sessionToken = new AutocompleteSessionToken();
tokenStatusElement.textContent = `Session token count: ${tokenCount}`;
}

declare global {
interface Window {
init: () => void;
}
}
window.init = init;
init();
// [END maps_place_autocomplete_data_session]
void 0; // No-op to preserve the last region tag comment.
export { };
51 changes: 46 additions & 5 deletions samples/place-autocomplete-data-session/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,55 @@ body {
padding: 0;
}

a {
.place-button {
height: 3rem;
width: 100%;
background-color: transparent;
text-align: left;
border: none;
cursor: pointer;
text-decoration: underline;
color: blue;
}

input {
.place-button:focus-visible {
outline: 2px solid #0056b3;
border-radius: 2px;
}

.input {
width: 300px;
font-size: small;
margin-bottom: 1rem;
}

/* Styles for the floating panel */
.controls {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
font-family: sans-serif;
font-size: small;
margin: 12px;
padding: 1rem;
}

.title {
font-weight: bold;
margin-top: 1rem;
margin-bottom: 0.5rem;
}

.results {
list-style-type: none;
margin: 0;
padding: 0;
}

.results li:not(:last-child) {
border-bottom: 1px solid #ddd;
}

.results li:hover {
background-color: #eee;
}

/* [END maps_place_autocomplete_data_session] */
/* [END maps_place_autocomplete_data_session] */