I am trying to create a 1 page map generator where they enter their address and postcode.
This part works
The Geolocation API then does a reverse lookup to get the longitude and latitude and populates it to 2 hidden input fields for later use.
This part doesn't work
I then need to use the Maps API to get the longitude and latitude values from the hidden inputs and generate the map, however, the variables are coming in NULL because they're set inside a function that's activated on click.
I need to be able to fire the map generator code after the value's have been set, or pass a set of values through initially from a set figure and then on click of the button re-run the code using the hidden values.
<script>
var apiKey='REMOVED FOR PRIVACY';
var longitude, latitude, map;
jQuery(document).ready(function( $ ) {
$('#find-address').click(function () {
var address = $('#address').val();
var postcode = $('#postcode').val();
var addressClean = address.replace(/\s+/g, '+');
var postcodeClean = postcode.replace(/\s+/g, '+');
var apiCall = 'https://maps.googleapis.com/maps/api/geocode/json?address='+addressClean+',+'+postcodeClean+'&key='+apiKey+'';
$.getJSON(apiCall,function (data, textStatus) {
longitude = data.results[0].geometry.location.lng;
latitude = data.results[0].geometry.location.lat;
document.getElementById("long").value = longitude;
document.getElementById("lat").value = latitude;
});
setTimeout(function(){
longitude = $("input#long").val();
latitude = $("input#lat").val();
if(longitude && latitude){
longitude = parseFloat(longitude);
latitude = parseFloat(latitude);
initMap(longitude,latitude);
}
}, 1000);
});
});
function initMap(longitude,latitude) {
var myLatlng = new google.maps.LatLng(latitude,longitude);
var mapOptions = {
zoom: 12,
center: myLatlng
}
var map = new google.maps.Map(document.getElementById("map-embed-div"), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
draggable: true,
title: "Where's your garden?"
});
};
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=REMOVED_FOR_PRIVACY&callback=initMap" async defer></script>
I've tried calling the function inside the setTimeout function and passing the values within the function callback however this returns NULL.
Moving everything inside the timeout function throws a promise error for initMap not being defined.
HTML Form
<form action="/instant-quote-test/#wpcf7-f3686-p3924-o1" method="post" class="wpcf7-form mailchimp-ext-0.5.14" novalidate="novalidate">
<div style="display: none;">
<input type="hidden" name="_wpcf7" value="3686" /><br />
<input type="hidden" name="_wpcf7_version" value="5.1.7" /><br />
<input type="hidden" name="_wpcf7_locale" value="en_GB" /><br />
<input type="hidden" name="_wpcf7_unit_tag" value="wpcf7-f3686-p3924-o1" /><br />
<input type="hidden" name="_wpcf7_container_post" value="3924" />
</div>
<p><span class="wpcf7-form-control-wrap your-fname"><input type="hidden" name="your-fname" value="" size="40" class="wpcf7-form-control wpcf7dtx-dynamictext wpcf7-dynamichidden" aria-invalid="false" /></span><span class="wpcf7-form-control-wrap your-email"><input type="hidden" name="your-email" value="" size="40" class="wpcf7-form-control wpcf7dtx-dynamictext wpcf7-dynamichidden" aria-invalid="false" /></span><span class="wpcf7-form-control-wrap your-phone"><input type="hidden" name="your-phone" value="" size="40" class="wpcf7-form-control wpcf7dtx-dynamictext wpcf7-dynamichidden" aria-invalid="false" /></span></p>
<input type="text" name="street-address" value="" size="40" class="wpcf7-form-control wpcf7-text wpcf7-validates-as-required" id="address" aria-required="true" aria-invalid="false" placeholder="Street Address" />
<input type="text" name="post-code" value="" size="40" class="wpcf7-form-control wpcf7-text wpcf7-validates-as-required" id="postcode" aria-required="true" aria-invalid="false" placeholder="Post Code" />
<input type="hidden" id="lat" value=""><input type="hidden" id="long" value="">
<input type="hidden" name="addressField1" value=""><input type="hidden" name="postcodeField" value="">
<a href="#" id="find-address" title="Find Address" class="button">Find Address</a>
<div id="map-embed">
<div id="map-embed-div" style="height:400px;width:100%;"></div>
</div>
<div id="after-map-quote">
<input type="submit" value="Get My Lawn Care Quote" class="wpcf7-form-control wpcf7-submit quote-send" />
</div>
</form>
There are several issues.
I get the JavaScript error: InvalidValueError: setCenter: not a LatLng or LatLngLiteral with finite coordinates: in property lat: NaN is not an accepted value
because in your API include:
you have callback=initMap
, but you don't want that to run on API load, you want it to run after the user clicks "Find Address". Remove that:
<script src="https://maps.googleapis.com/maps/api/js?key=REMOVED_FOR_PRIVACY" async defer></script>
Uncaught TypeError: Cannot read property 'geometry' of undefined
when I click "Find Address", because there is no error checking. If I check text status (with the Google test key at least) it tells me: "API keys with referer restrictions cannot be used with this API."
, status: "REQUEST_DENIED"
. If I use an unrestricted key for the request to the geocoder, I get a map with a marker (at least for a valid address). I would suggest using the Google JavaScript API v3 Geocoder, and adding error checking:var geocoder = new google.maps.Geocoder();
geocoder.geocode({
address: addressClean + "," + postcodeClean
}, function(results, status) {
console.log(status);
if (status == 'OK') {
console.log(results);
longitude = results[0].geometry.location.lng();
latitude = results[0].geometry.location.lat();
document.getElementById("long").value = longitude;
document.getElementById("lat").value = latitude;
// geocoder is asynchronous, do this in the callback function
longitude = $("input#long").val();
latitude = $("input#lat").val();
if (longitude && latitude) {
longitude = parseFloat(longitude);
latitude = parseFloat(latitude);
initMap(longitude, latitude);
}
} else alert("geocode failed")
});
code snippet:
var apiKey = 'AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk';
var longitude, latitude, map;
jQuery(document).ready(function($) {
$('#find-address').click(function() {
var address = $('#address').val();
var postcode = $('#postcode').val();
var addressClean = address.replace(/\s+/g, '+');
var postcodeClean = postcode.replace(/\s+/g, '+');
var apiCall = 'https://maps.googleapis.com/maps/api/geocode/json?address=' + addressClean + ',+' + postcodeClean + '&key=' + apiKey + '';
//$.getJSON(apiCall,function (data, textStatus) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({
address: addressClean + "," + postcodeClean
}, function(results, status) {
console.log(status);
if (status == 'OK') {
console.log(results);
longitude = results[0].geometry.location.lng();
latitude = results[0].geometry.location.lat();
document.getElementById("long").value = longitude;
document.getElementById("lat").value = latitude;
// geocoder is asynchronous, do this in the callback function
longitude = $("input#long").val();
latitude = $("input#lat").val();
if (longitude && latitude) {
longitude = parseFloat(longitude);
latitude = parseFloat(latitude);
initMap(longitude, latitude);
}
} else alert("geocode failed")
});
});
function initMap(longitude, latitude) {
var myLatlng = new google.maps.LatLng(latitude, longitude);
var mapOptions = {
zoom: 12,
center: myLatlng
}
var map = new google.maps.Map(document.getElementById("map-embed-div"), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
draggable: true,
title: "Where's your garden?"
});
};
})
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form action="/instant-quote-test/#wpcf7-f3686-p3924-o1" method="post" class="wpcf7-form mailchimp-ext-0.5.14" novalidate="novalidate">
<div style="display: none;">
<input type="hidden" name="_wpcf7" value="3686" /><br />
<input type="hidden" name="_wpcf7_version" value="5.1.7" /><br />
<input type="hidden" name="_wpcf7_locale" value="en_GB" /><br />
<input type="hidden" name="_wpcf7_unit_tag" value="wpcf7-f3686-p3924-o1" /><br />
<input type="hidden" name="_wpcf7_container_post" value="3924" />
</div>
<p><span class="wpcf7-form-control-wrap your-fname"><input type="hidden" name="your-fname" value="" size="40" class="wpcf7-form-control wpcf7dtx-dynamictext wpcf7-dynamichidden" aria-invalid="false" /></span><span class="wpcf7-form-control-wrap your-email"><input type="hidden" name="your-email" value="" size="40" class="wpcf7-form-control wpcf7dtx-dynamictext wpcf7-dynamichidden" aria-invalid="false" /></span>
<span
class="wpcf7-form-control-wrap your-phone"><input type="hidden" name="your-phone" value="" size="40" class="wpcf7-form-control wpcf7dtx-dynamictext wpcf7-dynamichidden" aria-invalid="false" /></span>
</p>
<input type="text" name="street-address" value="77 Mass Ave" size="40" class="wpcf7-form-control wpcf7-text wpcf7-validates-as-required" id="address" aria-required="true" aria-invalid="false" placeholder="Street Address" />
<input type="text" name="post-code" value="02139" size="40" class="wpcf7-form-control wpcf7-text wpcf7-validates-as-required" id="postcode" aria-required="true" aria-invalid="false" placeholder="Post Code" />
<input type="hidden" id="lat" value=""><input type="hidden" id="long" value="">
<input type="hidden" name="addressField1" value=""><input type="hidden" name="postcodeField">
<a href="#" id="find-address" title="Find Address" class="button">Find Address</a>
<div id="map-embed">
<div id="map-embed-div" style="height:400px;width:100%;"></div>
</div>
<div id="after-map-quote">
<input type="submit" value="Get My Lawn Care Quote" class="wpcf7-form-control wpcf7-submit quote-send" />
</div>
</form>
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk" async defer></script>