Skip to content

Instantly share code, notes, and snippets.

@philcon93
Last active April 30, 2020 12:01
Show Gist options
  • Save philcon93/db1feeb59b108dbebecf3294dccfb45e to your computer and use it in GitHub Desktop.
Save philcon93/db1feeb59b108dbebecf3294dccfb45e to your computer and use it in GitHub Desktop.
google address checkout

Google Address Auto Complete Checkout

B@SE JS

https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform

This uses Googles address auto complete to fill out a Neto checkout. Because of how Neto checkout works, we need to add in MutationObserver to check if the suburb has been updated by neto.checkout.js. Then we can add in the new field and then call the $.checkout_CalShipping() function to calulate shipping cost.

  • User places in their address,
  • Google will display a dropdown to autocomplete the address,
  • We bias the results to the users location,
  • When a user selects an address it will fill out all the correct fields,
  • Adding in a postcode will trigger a MutationObserver for the suburb, which we then add in the correct suburb,
  • This will then add in a country which will then calculate then shipping
// This displays an address form, using the autocomplete feature
// of the Google Places API to help users fill in the information.
var placeSearch, autocompleteBillAddress, autocompleteShipAddress, autocompleteMultiShipAddress;
var componentForm = {
subpremise: 'short_name',
street_number: 'short_name',
route: 'long_name',
locality: 'long_name',
administrative_area_level_2: 'short_name',
administrative_area_level_1: 'short_name',
country: 'short_name',
postal_code: 'short_name'
};
$(document).ready(function () {
// Custom MutationObserver for suburb select, in order to place Google surbub in correctly
// Select the target node
var suburbBill = document.getElementById('bill_selector');
var suburbShip = document.getElementById('ship_selector');
// var suburbMultiShip = document.getElementById('_addr_street1');
// Configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };
// Create an observer instance
var suburbObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if(mutation.addedNodes.length > 0){
var text = mutation.addedNodes["0"].childNodes["0"].innerHTML;
if(text !== 'Loading...'){
if(mutation.target.id == 'bill_selector'){ customSuburbSelector('b');}
else if (mutation.target.id == 'ship_selector'){ customSuburbSelector('s');}
// else{ customSuburbSelector('m');}
}
}
});
});
// Pass in the target node, as well as the observer options
if(suburbBill){ suburbObserver.observe(suburbBill, config);}
if(suburbShip){ suburbObserver.observe(suburbShip, config);}
// if(suburbMultiShip){ suburbObserver.observe(suburbMultiShip, config); }
});
// Returns Google Address object, based on which address it is coming from
function googleAddress(type){
if(type == 'b'){
return autocompleteBillAddress.getPlace();
}else{
return autocompleteShipAddress.getPlace();
}
}
// Sets the suburb from google address
function customSuburbSelector(type){
// Get the place details from the autocomplete object.
var place = googleAddress(type);
if(place !== undefined){
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentForm[addressType]) {
var val = place.address_components[i][componentForm[addressType]];
if(addressType == 'locality'){
if(type == 'b'){
if($('#bill_selector').css('display') == 'none'){
$('[data-google-b-role="'+addressType+'"]').val(val);
}else{
$('[data-google-b-role="'+addressType+'"]').val(val);
$('#bill_selector_cysel option').each(function(){
if($(this).val().indexOf(val.toUpperCase()) >= 0){
$(this).prop('selected', true);
}
});
}
}else{
if($('#ship_selector').css('display') == 'none'){
$('[data-google-s-role="'+addressType+'"]').val(val);
}else{
$('[data-google-s-role="'+addressType+'"]').val(val);
$('#ship_selector_cysel option').each(function(){
if($(this).val().indexOf(val.toUpperCase()) >= 0){
$(this).prop('selected', true);
}
});
}
}
}
}
}
customStateSelector(type);
}
}
// Sets the state from the google address
function customStateSelector(type){
// Get the place details from the autocomplete object.
var place = googleAddress(type);
if(place !== undefined){
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentForm[addressType]) {
var val = place.address_components[i][componentForm[addressType]];
if(addressType == 'administrative_area_level_1'){
if(type == 'b'){
if($('#bill_state_pl').css('display') == 'none'){
$('[data-google-b-role="'+addressType+'"]').val(val);
}else{
$('[data-google-b-role="'+addressType+'"]').val(val);
$('#bill_state_sel option').each(function(){
if($(this).val().indexOf(val.toUpperCase()) >= 0){
$(this).prop('selected', true);
}
});
}
}else{
if($('#ship_state_pl').css('display') == 'none'){
$('[data-google-s-role="'+addressType+'"]').val(val);
}else{
$('[data-google-s-role="'+addressType+'"]').val(val);
$('#ship_state_sel option').each(function(){
if($(this).val().indexOf(val.toUpperCase()) >= 0){
$(this).prop('selected', true);
}
});
}
}
}
}
}
recheckShipping();
}
}
// Gets all the correct fields and then calcualtes the shipping
function recheckShipping(){
var tparam = $.getCheckoutCache();
var loc = {
'addr_id': 0
};
if (tparam['address_fields']) {
var pf = tparam['ship_id'];
for (var k in tparam['address_fields']) {
var oid = pf + tparam['address_fields'][k];
var fld = $('#' + oid);
if (fld.length > 0) {
loc['ship_' + k] = fld.val();
}
}
}
if (tparam['address_fields']) {
var pf = tparam['bill_id'];
for (var k in tparam['address_fields']) {
var oid = pf + tparam['address_fields'][k];
var fld = $('#' + oid);
if (fld.length > 0) {
loc['bill_' + k] = fld.val();
}
}
}
$.checkout_CalShipping(loc);
}
// Fill in the address fields for multi address fields
function fillInMultiAddress(type){
var place = googleAddress(type);
// Get each component of the address from the place details and fill the corresponding field on the form.
var street_address = "";
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentForm[addressType]) {
var val = place.address_components[i][componentForm[addressType]];
if(addressType == 'subpremise' || addressType == 'street_number' || addressType == 'route'){
// Concat subpremise, street_number, into one field
if(addressType == 'subpremise'){ street_address += val+'/';}
else{ street_address += val+' ';}
}else if(addressType == 'postal_code'){
$('#_addr_zip').val(val);
// Trigger MutationObserver
$.load_city_selector('_addr_selector');
}else if(addressType == 'country'){
$('#_addr_country option').each(function(){
if($(this).val().indexOf(val.toUpperCase()) >= 0){ $(this).prop('selected', true); }
});
}else{
$('[data-google-'+type+'-role="'+addressType+'"]').val(val);
}
}
}
$('#_addr_street1').val(street_address);
}
// Fill in the address fields for billing or shipping address
function fillInAddress(type) {
// Get the place details from the autocomplete object.
if(type !== 'm'){
var place = googleAddress(type);
for (var component in componentForm) {
$('[data-google-'+type+'-role="'+component+'"]').val('');
$('[data-google-'+type+'-role="'+component+'"]').attr('disabled', false);
}
// Get each component of the address from the place details and fill the corresponding field on the form.
var street_address = "";
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentForm[addressType]) {
var val = place.address_components[i][componentForm[addressType]];
if(addressType == 'subpremise' || addressType == 'street_number' || addressType == 'route'){
// Concat subpremise, street_number, into one field
if(addressType == 'subpremise'){ street_address += val+'/';}
else{ street_address += val+' ';}
}else if(addressType == 'postal_code'){
$('[data-google-'+type+'-role="'+addressType+'"]').val(val);
// Trigger MutationObserver
if(type == 'b'){
$.load_city_selector('bill_selector');
}else{
$.load_city_selector('ship_selector');
}
}else if(addressType == 'country'){
// Find correct country
if(type == 'b'){
$('#bill_country option').each(function(){
if($(this).val().indexOf(val.toUpperCase()) >= 0){ $(this).prop('selected', true); }
});
$.postcode_change_country('bill_selector');
}else{
$('#ship_country option').each(function(){
if($(this).val().indexOf(val.toUpperCase()) >= 0){ $(this).prop('selected', true); }
});
$.postcode_change_country('ship_selector');
}
}else{
$('[data-google-'+type+'-role="'+addressType+'"]').val(val);
}
}
}
$('[data-google-'+type+'-role="route"]').val(street_address);
recheckShipping();
}else{
// fillInMultiAddress(type);
}
}
// Set up auto complete and event listeners
function initAutocomplete() {
// Create the autocomplete object, restricting the search to geographical location types.
autocompleteBillAddress = new google.maps.places.Autocomplete(
/** @type {!HTMLInputElement} */(document.getElementById('bill_street1')), {types: ['geocode']}
);
autocompleteShipAddress = new google.maps.places.Autocomplete(
/** @type {!HTMLInputElement} */(document.getElementById('ship_street1')),{types: ['geocode']}
);
// autocompleteMultiShipAddress = new google.maps.places.Autocomplete(
// /** @type {!HTMLInputElement} */(document.getElementById('_addr_street1')), {types: ['geocode']}
// );
// When the user selects an address from the dropdown, populate the address fields in the form.
autocompleteBillAddress.addListener('place_changed', function(){ fillInAddress('b'); });
autocompleteShipAddress.addListener('place_changed', function(){ fillInAddress('s'); });
// autocompleteMultiShipAddress.addListener('place_changed', function(){ fillInAddress('m'); });
}
// Bias the autocomplete object to the user's geographical location, as supplied by the browser's 'navigator.geolocation' object.
function geolocate() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var geolocation = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
var circle = new google.maps.Circle({
center: geolocation,
radius: position.coords.accuracy
});
autocompleteBillAddress.setBounds(circle.getBounds());
autocompleteShipAddress.setBounds(circle.getBounds());
// autocompleteMultiShipAddress.setBounds(circle.getBounds());
});
}
}
<!-- Example of the input that triggers the billing address and also is the field for route -->
<input class="form-control" type="text" name="bill_street1" id="bill_street1" maxlength="50" value="[@bill_street1@]"
data-google-b-role="route" onFocus="geolocate()"/>
<!-- Example of the shipping post code field -->
<input class="form-control" type="text" name="ship_zip" id="ship_zip" value="[@ship_zip@]" maxlength="10"
data-google-s-role="postal_code"/>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment