By all means please let us know how you have managed with connecting the Address Input to the Google Maps API.
One example for what you can do with this input element is to sort a list of places by their distance from the address a visitor has entered.
We hope to have an example that demonstrates a similar use case soon, but in a nutshell you can achieve this by:
Creating a Data Collection that holds the information about the places. In your case you’ll have a row for each student apartment, and columns for the name of the place, its address etc.
Connecting a Repeater to this collection using a Dataset. Each item in the repeater will display information about a single student apartment.
Adding an event handler for the onChange event of AddressInput and use the value property to obtain the location of the entered address in lat/lon GEO coordinates. Then you can calculate its distance from that of each place’s location (use their value property the same way) and sort the repeater items accordingly.
Please let me know if this is detailed enough or not. As said, I hope we have an example soon.
@eyalc an example showing that would be absolutely perfect! I am building a site right now that needs to show restaurants under events, but i want to take the approach ‘Restaurants near this event’…
I’m working with the address input but I realise that the valid method on the component only check if there is some text in the input field, not if an address has been selected.
It would be very useful to have an option that says: require valid address so the input is only valid if the user selected an address and not only if he typed something invalid
Thanks @quentin !
Yes, we plan to add an option to the Settings panel to give you control over whether visitors must select one of the suggestions (otherwise the Address Input switches into Error state), or are allowed to enter “free text”.
Will update when we start working on it.
I’ve received an update that it could take us a bit to publish an example for the Address Input (team in charge of the examples has higher priorities), so in the meantime I want to share with you a demo I created.
Frankly, the code (and explanations) is not on par with the standard of our examples, but I’ll do my best to help you with it.
First things first; head over to the demo , enter an address (in the UK) and find Cat Cafes nearby.
Next, let’s go over how I set up the Editor Elements and Data before I present the Corvid code.
Editor Elements used:
Address Input
Google Map
Repeater with information on the Cat Cafes. Each Repeater Item holds 3 Text Elements:
Name of the Cat Cafe
Its address
Its distance from the entered address
Data Collection and Dataset setup:
The Collection has two fields: ‘Name’ (Text) and ‘Address’ (Address)
I manually entered the details of 10 Cat Cafes in the UK
Corresponding Dataset is Read-only and displays 20 items at a go
Note that I made it easy on myself: because all items fit in a single Dataset Page I didn’t have to write code to handle multiple pages.
Connected Name & Address Text Elements to the corresponding fields
Google Map setup (AKA Welcome to the Realm of Workarounds):
Configured to Multiple Locations.
I would have liked to connect the element to the addresses in the Cat Cafes collection, but unfortunately this is not supported yet (hint hint).
As a fallback, I would have liked to retrieve these addresses in code and set them to the location property, but alas, setting multiple locations through code is not supported yet either (yes, hint hint, I get it).
So instead I manually entered 11 addresses: the first one is a placeholder that will be used to set the address the visitor will enter (I set its default location to Buckingham Palace), the other addresses are duplicates of those in the data collection.
Finally, the code:
HTH
I’m here for questions, which I bet you have
//===== Init =====
var catCafesData = null ;
export async function catCafes_ready() {
// Fetch Cat Cafes data once (it is static) and keep it in a global variable.
//===== Init =====
var catCafesData = null;
export async function catCafes_ready() {
// Fetch Cat Cafes data once (it is static) and keep it in a global variable.
catCafesData = await getCatCafesData($w('#catCafes'));
// Set the default address to be the first Google Maps location, which is used as the placeholder for the visitor entered address.
let DEFAULT_VISITOR_ADDRESS = $w('#googleMaps1').location;
// Display distances of all Cat Cafes from this address and sort them by it.
displayDistances(DEFAULT_VISITOR_ADDRESS);
sortByDistance();
}
function getCatCafesData(catCafesDataset) {
return catCafesDataset.getItems(0, catCafesDataset.getPageSize())
.then((result) => {
return result.items;
})
}
//===== Event Handlers =====
export async function addressInput1_change(event) {
let address = $w('#addressInput1').value;
if (!address || !address.location) return;
viewAddressOnMap(address);
displayDistances(address.location);
sortByDistance();
}
//===== View address on Google Maps =====
function viewAddressOnMap(address) {
if (!address || !address.location) return;
$w("#googleMaps1").location = {
"latitude": address.location.latitude,
"longitude": address.location.longitude,
"description": address.formatted
};
}
//===== Display and sort Cat Cafes (Repeater items) by distance from an address =====
function displayDistances(addressLocation) {
let catCafeNameToDistance = catCafesData.reduce((map, item) => (map[item.title] = getDistanceFromLatLonInKm(addressLocation.latitude, addressLocation.longitude, item.address.location.lat, item.address.location.lng), map), {});
// Add the distance of the address from each Cat Cafe on the Repeater data. We will need if for sorting.
$w("#catCafesInfo").data = $w("#catCafesInfo").data.map((item) => { item['distance'] = catCafeNameToDistance[item.title]; return item });
// Update the distance text indication for each Repeater item.
$w("#catCafesInfo").forEachItem(($item, itemData, index) => {
$item("#catCafeDistance").text = itemData.distance.toFixed(2) + ' km';
});
}
function sortByDistance() {
$w("#catCafesInfo").data = $w("#catCafesInfo").data.sort(
function (item1, item2) {
let d1 = item1.distance;
let d2 = item2.distance;
if (d1 < d2) {
return -1;
}
if (d1 > d2) {
return 1;
}
return 0;
}
);
}
//===== Lat/lon distance calculations =====
// I simply copied it from: https://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula
function deg2rad(deg) {
return deg * (Math.PI / 180)
}
function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1);
var dLon = deg2rad(lon2 - lon1);
var a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c; // Distance in km
return d;
}
@quentin I submitted a request add the turfjs package. Do mind though that only backend packages are supported, so the distance calculations would have to take place there.