#WebModules #ServerSide #GoogleMaps #GeoLocation #3rdPartyServices
Note: The app presented in this post is now available as an Example template that can be loaded into the Wix Editor. See the post Example: Using the Places API from Google Maps services.
:: Places example application (without map) ::
Here is a screenshot of what the app looks like while typing in a location for lookup. Notice the dropdown menu, created with a Repeater, directly under the text input field.
After the app performs the lookup (using Google Maps web services), the result looks like this:
Another thing you'll notice is that I chose perfectly barfy colors. My excuse is that I'm a developer/writer and not a designer.
Demonstrates
Web modules - server-side (backend) code
Accessing 3rd Party Services (using backend function)
fetch() in the wix-fetch API
getCurrentGeolocation() in the wix-window API to retrieve the user's IP-based location coordinates
wix-storage API for persistent storage of the selected location
Repeater (create list, expand / collapse)
Required for this example
In order to run this example, you will need to supply your own Google Maps API key.
About this example app
There are many instances when you want to find the exact coordinates of a location, or given the coordinates, discover the name of the location. In this article, we demonstrate geolocation queries using the Google Maps API web services to perform location details lookups and reverse location lookups. This example also demonstrates how to call these backend Web modules. Web modules are quite useful when you have security concerns such as protecting your code from prying eyes and preventing access to your web services API keys.
If you don’t have a location currently defined for the app, the getCurrentGeolocation() function of the wix-window API retrieves the current location based on your local IP address. After retrieving the coordinates of your location, the reverse() function (in the backend) invokes the reverse geolocation lookup from the Google Maps service to get the name and details of your location. You can always retrieve your current location by clicking on the “place” icon next to the input field.
You can retrieve details of other locations by entering in the location name in the text input field. As you type, the autocomplete() function (in the backend) will return predictions (I call them “suggestions”) that are supplied by the Google Maps service. The list of suggestions is displayed in a repeater which is displayed directly under the input field. If one of the listed locations is the one you want, click on that name. Otherwise, continue to enter in your name. The more you type, the more targeted the suggestions list becomes.
Once you’ve selected a location, or clicked on the “current location” icon, the details() function is called asking Google Maps to supply details about your desired location. The code then saves your latest selection in persistent storage using the wix-storage API.
App Web Page
We start by creating a simple page with the following components:
Page components details:
repeater1 has two text fields and is used as a dropdown menu.
● text1 is a suggestion list item (place name):
● text2 is a hidden field that holds the unique place ID assigned by Google:
repeater2 has two text fields and displays details of the selected place.
● text3 displays the title of the place detail:
● text4 displays the value of the place detail:
Backend Functions
Create a web module (backend) file named gapi.jsw (short for Google API).
In this file, create three web modules which will be used to call the Google Maps online service functions. Web modules are required to have a .jsw extension. We use the wix-fetch API to access the online services, so we will need an import statement at the top of the file:
import {fetch} from 'wix-fetch';
Google requires an API key to access their services. Get an API key of your own, and then add it to the file directly after the import statement:
const key = "Crazy-long_Google_API-key"; // your own API key here
Place autocomplete suggestions
This web module function returns a list of place "suggestions" based on the user's input in the textInput field.
const apart1 = "https://maps.googleapis.com/maps/api/place/autocomplete/json?";
const apart2 = "&types=(cities)&key=";
export function autocomplete(string) {
let input = "input=" + string;
let url = apart1 + input + apart2 + key;
return fetch (url, {method: 'get'}).then( (httpResponse) => {
if (httpResponse.ok) {
return httpResponse.json();
}
});
}
Retrieve details of the selected location
This web module function uses the unique place_id to retrieve details for the current or selected location.
const dpart1 = "https://maps.googleapis.com/maps/api/place/details/json?";
const dpart2 = "&key=";
export function details(id) {
let placeid = "placeid=" + id;
let url = dpart1 + placeid + dpart2 + key;
return fetch (url, {method: 'get'}).then( (httpResponse) => {
if (httpResponse.ok) {
return httpResponse.json();
}
});
}
Reverse geolocation
This web module function returns location name(s) based on the location's coordinates.
const rpart1 = "https://maps.googleapis.com/maps/api/geocode/json?";
const rpart2 = "&key=";
export function reverse(lat, lng) {
let latlng = "latlng=" + lat + "," + lng;
let url = rpart1 + latlng + rpart2 + key;
return fetch (url, {method: 'get'}).then( (httpResponse) => {
if (httpResponse.ok) {
return httpResponse.json();
}
});
}
Page Code
Now that we have the backend functions, we have to wire up everything and call these backend functions from the web page itself. In the Page Code of the app, the first thing we need to do is to import the Wix APIs that we are using, and our web modules (backend).
import wixWindow from 'wix-window';
import {local} from 'wix-storage';
import {autocomplete} from 'backend/gapi';
import {details} from 'backend/gapi';
import {reverse} from 'backend/gapi';
$w.onReady()
In the page’s $w.onReady() function, we configure the behavior of the repeaters, and set up the page.
$w.onReady(function () {
// handle each suggestion repeater item
$w("#repeater1").onItemReady( ($w, itemData, index) => {
const text1 = $w("#text1");
text1.text = itemData.text1;
const text2 = $w("#text2");
text2.text = itemData.text2;
});
$w("#repeater1").collapse(); // hidden on page load
// handle each location detail line
$w("#repeater2").onItemReady( ($w, itemData, index) => {
const text3 = $w("#text3");
text3.text = itemData.text3;
const text4 = $w("#text4");
text4.text = itemData.text4;
});
$w("#repeater2").hide(); // hidden on page load
// retrieve saved location (if exists) from local storage
let id = local.getItem("place_id");
if(id === undefined || id === null || id.length === 0) {
// if no location saved, find the IP-based geographic location
geoloc();
}
else {
// if a location was saved in local storage, get the details
set_details(id);
}
});
Autocomplete suggestions with a "homemade" dropdown
As you type a location name in the text input field, the onKeyPress event calls the autocomplete() web module to retrieve a list of place suggestions (predictions). The suggestions received from Google Maps will be presented in a dropdown created with a $w.Repeater component.
export function input1_keyPress(event, $w1) {
$w("#repeater2").data = [];
$w("#repeater2").hide();
setTimeout(() => {
// use the current value to get a list of location suggestions
// we call the autocomplete() web module from the backend
let val = event.target.value;
if(val.length === 0)
return; // ignore if empty
autocomplete(val).then(function (resp) {
// create an array of suggestions for the repeater
let predictions = resp.predictions;
let suggestions = [];
predictions.forEach(function (prediction) {
let item = { "_id": prediction.id, "text1": prediction.description, "text2": prediction.place_id };
suggestions.push(item);
});
$w("#repeater1").data = suggestions; // add the suggestions to the repeater
$w("#repeater1").expand(); // we have data so we can expand the repeater
});
}, 10);
}
Select a location from the Repeater dropdown menu
When you click on one of the suggestions displayed by Repeater dropdown menu, the following function is triggered to retrieve the details of the newly selected location.
// this function is triggered when clicking on a suggestion list repeater item
export function container1_click(event, $w) {
let place_id = $w("#text2").text;
set_details(place_id);
$w("#repeater1").collapse();
}
Get the details of the location
This function calls the details() web module to retrieve the details (city, country, utc, etc) of the selected or saved location.
function set_details(val) {
details(val).then(function(resp) {
// find the city (locality) and country of the location
let place = resp.result;
var filtered_array = place.address_components.filter(function(address_component){
return address_component.types.includes("country");
});
var country = filtered_array.length ? filtered_array[0].long_name: "";
filtered_array = place.address_components.filter(function(address_component){
return address_component.types.includes("locality");
});
var locality = filtered_array.length ? filtered_array[0].long_name: "";
console.log("details: " + locality);
let name = place.formatted_address;
let id = place.place_id;
let utc = place.utc_offset;
let lat = place.geometry.location.lat;
let lng = place.geometry.location.lng;
// save the details of the location with wix-storage
local.setItem("place_city", name);
local.setItem("place_lat", lat);
local.setItem("place_lng", lng);
local.setItem("place_utc", utc);
local.setItem("place_id", id);
$w("#input1").value = name; // set input field to location
// array of location detail items for the repeater
let detailsList =
[
{
"_id": "1",
"text3": "place name",
"text4": name
},
{
"_id": "2",
"text3": "latitude",
"text4": "" + lat
},
{
"_id": "3",
"text3": "longitude",
"text4": "" + lng
},
{
"_id": "4",
"text3": "utc",
"text4": "" + utc
},
{
"_id": "5",
"text3": "place id",
"text4": id
}
];
// set the details repeater data and show it
$w("#repeater2").data = detailsList; // add data to our repeater
$w("#repeater2").show();
});
}
Get current IP-based location
If you click on the “here” icon next to the text input field, the vectorImage1_click() function is triggered and calls the geoloc() function to retrieve your IP-based location.
export function vectorImage1_click(event, $w) {
// clear the details to get ready for the "here" location
$w("#repeater2").data = [];
$w("#repeater2").hide();
geoloc();
}
This function calls the getCurrentGeolocation() in the wixWindow API to retrieve your IP-based location. If the Google Maps service does not return any location (ZERO_RESULTS), then the default will be Pittsburgh, PA.
export function geoloc() {
wixWindow.getCurrentGeolocation()
.then( (obj) => {
let lat = obj.coords.latitude;
let lng = obj.coords.longitude;
reverse(lat, lng).then(function(resp) {
let status = resp.status;
if(status === "ZERO_RESULTS") {
let name = "Pittsburgh, PA, USA";
local.setItem("place_city", name);
local.setItem("place_lat", "40.44062479999999");
local.setItem("place_lng", "-79.9958864");
local.setItem("place_utc", "-300");
local.setItem("place_id", "ChIJA4UGSG_xNIgRNBuiWqEV-Y0");
$w("#input1").value = name;
return;
}
let results = resp.results;
var country = null, city = null, place_id = null;
var c, lc, component;
for (var r = 0, rl = results.length; r < rl; r += 1) {
let result = results[r];
// look for city (locality) and country
if (!city && result.types[0] === 'locality') {
for (c = 0, lc = result.address_components.length; c < lc; c += 1) {
component = result.address_components[c];
if (component.types[0] === 'locality') {
city = component.long_name;
continue;
}
if (component.types[0] === 'country') {
country = component.long_name;
if(city && country)
break;
}
}
}
else {
continue;
}
if (city && country) {
place_id = result.place_id;
set_details(place_id);
break;
}
}
});
} )
.catch( (error) => {
let errorMsg = error;
console.log(errorMsg);
});
}
This is a very old thread that is not being monitored. If you have any questions or comments, please create a new post in Community Discussion. Thank you!