Latitude: ${detailsResult.geometry.location.lat.toFixed(5).toString()}
Longitude: ${detailsResult.geometry.location.lng.toFixed(5).toString()}
`
+ );
+ if (detailsResult.address_components) {
+ const compoHtml = detailsResult.address_components
+ .map(
+ (compo) =>
+ `Address components
${compoHtml}
`
+ );
+ }
+ }
+ detailsHTML.innerHTML = details.join("");
+}
+
+const inputElement = document.getElementById(
+ "autocomplete-input"
+) as HTMLInputElement;
+const suggestionsList = document.getElementById(
+ "suggestions-list"
+) as HTMLUListElement;
+const clearSearchBtn = document.getElementsByClassName(
+ "clear-searchButton"
+)[0] as HTMLButtonElement;
+detailsResultContainer = document.querySelector(
+ ".detailsResult"
+) as HTMLElement;
+detailsHTML = document.querySelector(
+ ".detailsResult .detailsOptions"
+) as HTMLElement;
+if (inputElement && suggestionsList) {
+ inputElement.addEventListener("input", handleAutocomplete);
+ inputElement.addEventListener("keydown", (event) => {
+ if (event.key === "Enter") {
+ const firstLi = suggestionsList.querySelector("li");
+ if (firstLi) {
+ firstLi.click();
+ }
+ }
+ });
+}
+clearSearchBtn.addEventListener("click", () => {
+ inputElement.value = "";
+ suggestionsList.style.display = "none";
+ clearSearchBtn.style.display = "none";
+ if (marker) {
+ marker.setMap(null);
+ infoWindow.close();
+ }
+ inputElement.focus();
+});
+
+function handleAutocomplete(): void {
+ if (inputElement && suggestionsList) {
+ input = inputElement.value;
+ if (input) {
+ debouncedLocalitiesSearch(input)
+ .then((results) => displaySuggestions(results))
+ .catch((error) =>
+ console.error("Error autocomplete localities:", error)
+ );
+ } else {
+ suggestionsList.style.display = "none";
+ clearSearchBtn.style.display = "none";
+ }
+ }
+}
+
+function handleDetails(publicId: string) {
+ localitiesService
+ .getDetails({ publicId })
+ .then((response) => displayResult(response.result))
+ .catch((error) => console.error("Error getting locality details:", error));
+}
+
+function displaySection(section: HTMLElement, mode = "block"): void {
+ section.style.display = mode;
+}
+
+function displayResult(result: woosmap.map.localities.LocalitiesDetailsResult) {
+ fillDetailsResult(result);
+ displaySection(detailsResultContainer);
+ if (marker) {
+ marker.setMap(null);
+ infoWindow.close();
+ }
+ if (result?.geometry) {
+ marker = new woosmap.map.Marker({
+ position: result.geometry.location,
+ icon: {
+ url: "https://images.woosmap.com/marker.png",
+ scaledSize: {
+ height: 50,
+ width: 32,
+ },
+ },
+ });
+ marker.setMap(map);
+ infoWindow.setContent(
+ `
${result.formatted_address ?? result.name}`
+ );
+ infoWindow.open(map, marker);
+ map.flyTo({ center: result.geometry.location, zoom: 14 });
+ }
+}
+
+function displaySuggestions(localitiesPredictions: any) {
+ if (inputElement && suggestionsList) {
+ suggestionsList.innerHTML = "";
+ if (localitiesPredictions.results.length > 0 && input) {
+ localitiesPredictions.results.forEach((result) => {
+ const li = document.createElement("li");
+ const title = document.createElement("div");
+ const desc = document.createElement("span");
+ title.textContent = result.title ?? "";
+ title.className = "localities-search-title";
+ desc.textContent = result.description ?? "";
+ desc.className = "localities-search-description";
+ li.addEventListener("click", () => {
+ inputElement.value = result.title ?? "";
+ suggestionsList.style.display = "none";
+ handleDetails(result.public_id);
+ });
+ suggestionsList.appendChild(li);
+ li.appendChild(title);
+ title.appendChild(desc);
+ if (result.categories) {
+ const category = document.createElement("span");
+ category.textContent = result.categories[0];
+ category.className = "localities-search-category";
+ title.appendChild(category);
+ } else {
+ const type = document.createElement("span");
+ type.textContent = result.types[0];
+ type.className = "localities-search-type";
+ title.appendChild(type);
+ }
+ });
+ suggestionsList.style.display = "block";
+ clearSearchBtn.style.display = "block";
+ } else {
+ suggestionsList.style.display = "none";
+ }
+ }
+}
+
+document.addEventListener("click", (event) => {
+ const targetElement = event.target as Element;
+ const isClickInsideAutocomplete = targetElement.closest(
+ "#autocomplete-container"
+ );
+
+ if (!isClickInsideAutocomplete && suggestionsList) {
+ suggestionsList.style.display = "none";
+ }
+});
+
+// [START woosmap_localities_search_debounce_promise]
+let PRESERVE_COMMENT_ABOVE; // force tsc to maintain the comment above eslint-disable-line
+
+type DebouncePromiseFunction
= (
+ ...args: Args
+) => Promise;
+
+function debouncePromise(
+ fn: (...args: Args) => Promise,
+ delay: number
+): DebouncePromiseFunction {
+ let timeoutId: ReturnType | null = null;
+ let latestResolve: ((value: T | PromiseLike) => void) | null = null;
+ let latestReject: ((reason?: any) => void) | null = null;
+
+ return function (...args: Args): Promise {
+ return new Promise((resolve, reject) => {
+ if (timeoutId !== null) {
+ clearTimeout(timeoutId);
+ }
+ latestResolve = resolve;
+ latestReject = reject;
+ timeoutId = setTimeout(() => {
+ fn(...args)
+ .then((result) => {
+ if (latestResolve === resolve && latestReject === reject) {
+ resolve(result);
+ }
+ })
+ .catch((error) => {
+ if (latestResolve === resolve && latestReject === reject) {
+ reject(error);
+ }
+ });
+ }, delay);
+ });
+ };
+}
+
+// [END woosmap_localities_search_debounce_promise] */
+PRESERVE_COMMENT_ABOVE; // force tsc to maintain the comment above eslint-disable-line
+
+declare global {
+ interface Window {
+ initMap: () => void;
+ }
+}
+window.initMap = initMap;
+// [END woosmap_localities_search]
+
+export {};
diff --git a/samples/localities-search/localities-search.json b/samples/localities-search/localities-search.json
new file mode 100644
index 00000000..25dc5f24
--- /dev/null
+++ b/samples/localities-search/localities-search.json
@@ -0,0 +1,14 @@
+{
+ "title": "Localities Search",
+ "description": "Use the LocalitiesService to autocomplete and get details of localities, postal codes or addresses.",
+ "category": "Localities",
+ "callback": "initMap",
+ "tag": "localities_search",
+ "name": "localities-search",
+ "pagination": {
+ "data": "mode",
+ "size": 1,
+ "alias": "mode"
+ },
+ "permalink": "samples/{{ page.fileSlug }}/{{mode}}/{% if mode == 'jsfiddle' %}demo{% else %}index{% endif %}.{{ page.outputFileExtension }}"
+}
\ No newline at end of file
diff --git a/samples/localities-search/style.scss b/samples/localities-search/style.scss
new file mode 100644
index 00000000..7b7368b1
--- /dev/null
+++ b/samples/localities-search/style.scss
@@ -0,0 +1,92 @@
+@use 'sass:meta'; // To enable @use via meta.load-css and keep comments in order
+
+/* [START woosmap_localities_search] */
+@include meta.load-css("../../shared/scss/_default.scss");
+@include meta.load-css("../../shared/scss/_autocomplete_input.scss");
+@include meta.load-css("../../shared/scss/_autocomplete_list.scss");
+
+#app {
+ height: 100%;
+}
+
+.localities-search-title {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 0.2rem;
+}
+
+.localities-search-description {
+ font-weight: lighter;
+ color: #333;
+ font-size: 0.8rem;
+}
+
+.localities-search-category {
+ color: #c46500;
+ font-size: 0.7rem;
+ font-style: italic;
+ align-self: flex-end;
+}
+
+.localities-search-type {
+ color: #000000;
+ font-size: 0.7rem;
+ font-style: italic;
+ align-self: flex-end;
+}
+
+
+.detailsResult {
+ display: none;
+ position: absolute;
+ right: 10px;
+ bottom: 25px;
+ border-radius: 6px;
+ max-width: 240px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2), 0 -1px 0px rgba(0, 0, 0, 0.02);
+ z-index: 1;
+ overflow: hidden;
+
+ .info {
+ padding: 12px 16px;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.06);
+ background-color: #fff;
+ }
+
+ .detailsOptions {
+ overflow-y: auto;
+ max-height: 240px;
+ font-size: 12px;
+ padding-top: 12px;
+ background-color: #fff;
+
+ .option-detail {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 0 12px 8px 12px;
+ margin: 0;
+
+ &-label {
+ color: rgba(0, 0, 0, 0.5);
+ margin-right: 4px;
+ }
+ }
+ }
+ }
+
+ .address-components {
+ padding: 0 0 18px 0;
+ background-color: rgba(0, 0, 0, 0.03);
+ }
+
+ .address-components .title {
+ color: rgba(0, 0, 0, 0.5);
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ padding: 16px 12px 10px 12px;
+ }
+
+
+/* [END woosmap_localities_search] */