I am building a page which contains a form with 2 text input boxes, search_term and search_location. This allows the site user to search for a place near a particular location. To prevent hitting the API limit, I need to geocode clientside the user-inputted address from search_location text input box to a LatLng coordinate, which will be passed in $_POST[] to a PHP function which will access the relevant records in the MySQL database.
This is how I think it should work:
User types in address/zipcode into search_location text input box & a keyword into the search_term text input box.
When the Submit button is clicked, a JS event handler will use the Google Geocoder API to geocode the result and return the LatLng coordinates.
The LatLng coordinates is passed to the PHP function which accesses it as a POST variable, and access the database to retrieve the required results.
The Question:
I do not know how I can submit the form after getting the geocoded result from Google Geocoder API so I can pass the LatLng coordinates along in POST. At the moment, the form passes the user-inputted values in search_term and search_location input boxes.
Basically you need to set 2 hidden fields (one for lat and another for lng unless you want to save them as 1 string) and save the coords to it and then submit the form:
your form:
<form id='codeForm' action='some.php'>
<input type='text' name='search_location'>
<input type='text' name='search_term'>
<input type='hidden' name='lat'>
<input type='hidden' name='lng'>
<input type="button" value="Search" onclick="codeAddress()">
</form>
In the form I used a button type if you use a submit button you need to cancel the submit action until google returns a response or use onSubmit() event for the form.
Your geocode js function:
function codeAddress() {
myForm = document.forms["codeForm"]
//get the address
var address = myForm.elements["search_location"].value;
geocoder.geocode( { 'address': address}, function(results, status) {
//geocode was successful
if (status == google.maps.GeocoderStatus.OK) {
//grab the lat and long
lat = results[0].geometry.location.lat
lng = results[0].geometry.location.lng
myForm.elements["lat"].value=lat
myForm.elements["lng"].value=lng
//submit form
myForm.submit();
} else {
//geocode failed
alert("Geocode was not successful for the following reason: " + status);
}
});
}
My slightly modified code to Michael's above, which unfortunately doesn't work out of the box. I feel it's important to highlight this, because Google takes me to this post when I search for "geocode client side hidden fields". I'm taking the following code directly from my site, which uses $_GET, but it works either way. We start with the form:
<form type="get" id='codeForm' action='index.php'>
<input type='text' name='search_location' id='search_location'>
<input type='text' name='search_term'>
<input type="submit" value="Search" id="submitform">
<input type='text' name='search_term'>
</form>
As you can see, I've taken away the hidden lat and lng input fields from the form and appended them with jquery below:
<script type="text/javascript">
function codeAddress() {
myForm = document.forms["codeForm"];
//get the address
var geocoder = new google.maps.Geocoder();
var address = document.getElementById('search_location').value;
geocoder.geocode({'address': address, componentRestrictions:{country:"uk"}}, function(results, status) {
//geocode was successful
if (status == google.maps.GeocoderStatus.OK) {
//grab the lat and long
var lat = results[0].geometry.location.lat();
$("#codeForm").append("<input type='hidden' name='lat' value='" + lat + "' />");
var lng = results[0].geometry.location.lng();
$("#codeForm").append("<input type='hidden' name='lng' value='" + lng + "' />");
//submit form
} else {
//geocode failed
alert("Geocode was not successful for the following reason: " + status);
}
});
}
$(document).ready(function() {
$('#codeForm').submit(function(e) {
var form = this;
e.preventDefault();
codeAddress();
setTimeout(function () {
form.submit();
}, 1000); // in milliseconds
return false;
});
});
</script>
The important point about my code is that I have added a setTimeout delay, thanks to this post on SO. Without the delay, I found that the values in Michal's solution above were not being appended in time.
As a footnote, I know that I could improve upon the mix of javascript and jquery in my solution, but importantly it's a working example, and it's up to each and everyone to modify should they wish.
Related
I am trying to use Javascript for finding user location but it is not giving me any value, my code is below
<script>
window.onload = function() {
var startPos;
var geoSuccess = function(position) {
startPos = position;
document.getElementById('startLat').innerHTML = startPos.coords.latitude;
document.getElementById('startLon').innerHTML = startPos.coords.longitude;
};
navigator.geolocation.getCurrentPosition(geoSuccess);
};
</script>
<?php echo "<script> getCurrentPosition('startLat') </script>"; ?>
The HTML5 Geolocation API allows you to get a user's Latitude/Longitude with some JavaScript (if the browser is compatible, and if the user allows access to his/her location).
You can then reverse-geocode the location to get an address, there are several free reverse-geocoding services other than Google's API.
you can also check out this link How to get geographical location of an IP address in PHP for more understanding
Example:
<script>
var x = document.getElementById("demo");
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
x.innerHTML = "Geolocation is not supported by this browser.";
}
}
function showPosition(position) {
x.innerHTML = "Latitude: " + position.coords.latitude +
"<br>Longitude: " + position.coords.longitude;
}
</script>
If you have elements with id's "startLat" and "startLon" in your HTML, it'll work
Just add in HTML:
<p id="startLat"></p>
<p id="startLon"></p>
You can delete this line, actually:
<?php echo "<script> getCurrentPosition('startLat') </script>"; ?>
To use Latitude/Longitude in your PHP you can send the values via JS
In HTML
<script>
function sendData(value) {
var request = new XMLHttpRequest();
request.open('post', 'DESTINATION.PHP', true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send('data=' + value);
}
</script>
Or as a hidden form input
and access in PHP
if(isset($_POST['data'])){
$data = $_POST['data'];
// Do stuff...
}
I uploaded the web app that I'm working on to a remote server.
Everything is working good, except for the geolocation. I can't understand what is the problem, beacuse I didn't receive any error message.
this the HTML code where geolocation is involved.
<tr>
<td>Ti trovi qui: <span id="location"></span></td>
</tr>
</table>
<input type="hidden" id="latitude" name="latitude">
<input type="hidden" id="longitude" name="longitude">
</form>
These are the scripts that I use: (i'm not very prepared with javascript and jQuery)
function showLocation(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
jQuery.ajax({
type:'POST',
url:'getLocation.php',
data:'latitude='+latitude+'&longitude='+longitude,
success:function(msg){
if(msg){
jQuery("#location").html(msg);
}else{
jQuery("#location").html('Not Available');
}
}
});
}
function getUserCoordinates(position){
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
document.getElementById('latitude').value=latitude
document.getElementById('longitude').value=longitude
}
jQuery(document).ready(function(){
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getUserCoordinates);
navigator.geolocation.getCurrentPosition(showLocation);
} else {
jQuery('#location').html('Geolocation is not supported by this browser.');
}
});
This is getLocation.php file (but I don't think it's the problem):
<?php
require_once 'metodi.php';
sec_session_start();
if(login_check() == true){
if(!empty($_POST['latitude']) && !empty($_POST['longitude'])){
$_SESSION['latitude'] = $_POST['latitude'];
$_SESSION['longitude'] = $_POST['longitude'];
//Send request and receive json data by latitude and longitude
$url = 'http://maps.googleapis.com/maps/api/geocode/json?latlng='.trim($_POST['latitude']).','.trim($_POST['longitude']).'&sensor=false';
$json = #file_get_contents($url);
$data = json_decode($json);
$status = $data->status;
if($status=="OK"){
//Get address from json data
$location = $data->results[0]->formatted_address;
}else{
$location = '';
}
//Print address
echo $location;
}
} else {
echo "Non sei autorizzato a visualizzare questa pagina. Effettua il login.";
}
?>
Then I grab the value of hidden inputs in another php file.
If your website is running in https, you also need to change this
http://maps.googleapis.com/maps/api/geocode/json?latlng=
to this
https://maps.googleapis.com/maps/api/geocode/json?latlng=
getCurrentPosition() is asynchronous. When you call it twice there is no guarantee that the first call will complete before the second one does. It also makes no sense to call it twice back to back
Also it relies on third party service to return the data
Only call it once, and pass the response values to both of your functions inside one callback
Change
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getUserCoordinates);
navigator.geolocation.getCurrentPosition(showLocation);
} else {
To
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position){
getUserCoordinates(position);
showLocation(position);
});
} else {
Also check that you haven't disabled geolocation in your browser for the the remote domain. Add some console logging to see what is and isn't running within the code
One of my form fields is address. Before sending it to the server I want to transform it to latitude and longitude. This requires sending asynchronous request to some external service (e.g. Google Maps API). What's the proper way to do this?
My geocoding snippet:
function geocodeAddress() {
var address = document.getElementById("address").value;
geocoder.geocode({"address": address}, function(results, status) {
if (status === google.maps.GeocoderStatus.OK) {
var lat = results[0].geometry.location.lat()
document.getElementById("latitude").value = lat
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
I see several options:
Use onsubmit event handler - first return false (to wait for geocoding to complete), then in a separate callback set latitude field and submit form.
Use onchange event handler for address field - this requires blocking submit button until we geocode the address; it's also tricky if we prepopulate form values after submit it (e.g. filter rows)
Obviously I can also parse it on the server side, but this may result in one user using all my "quota" in the external service and I'd have to implement some kind of fairness, which I'd like to avoid.
So what's the proper way to solve this kind of pre-processing of form values in javascript?
You could consider the following approach:
prevent default behavior of button via Event.preventDefault()
resolve address via google.maps.Geocoder.geocoder function
once the address is resolved resume form submit: form.submit()
Example
function saveData(e) {
e.preventDefault(); //1.stop default behaviour of button
var address = document.getElementById("txtAddress").value;
resolveAddress(address,
function(results) {
document.getElementById("txtLat").value = results[0].geometry.location.lat();
document.getElementById("txtLng").value = results[0].geometry.location.lng();
document.getElementsByTagName('form')[0].submit(); //2.resume form submit
},
function(status) {
console.log('An error occured while resolving an address');
});
}
function resolveAddress(address,success,error) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ "address": address }, function (results, status) {
if (status === google.maps.GeocoderStatus.OK) {
success(results);
} else {
error(status);
}
});
}
Plunker
Been through a number of questions and nothing seems to work for my case.
Okay so, I have a form with a single input (search) field and a submit button. When the user enters a value (an address in this case) and hits submit, that address value needs to be sent to a JavaScript function which converts it into Longitude and Latitude values, and then these coordinates need to be sent to the destination page instead of the address they input.
Here is my code so far:
HTML
<form name="searchform" action="required/results.php" method="get" id="searchbar" onsubmit="convertToCoords()">
<input type="text" name="input" id="address" placeholder="Search an address or suburb...">
<input type="submit" class="searchbtn" value="Search">
</form>
JS
function convertToCoords() {
var address = document.getElementById("address").value; // Get the input address from the textbox
/* Address to Coordinates conversion (Disregard) */
geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// Get the Lat. and Long.
var searchedLat = results[0].geometry.location.lat();
var searchedLong = results[0].geometry.location.lng();
// Set address input value to coordinates, then submit form
document.getElementById('address').value = searchedLat + ',' + searchedLong;
document.getElementById('searchbar').submit();
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
PHP on destination page (for testing)
<?php
if (isset($_GET['input'])) {
echo $_GET['input']; // get value of search input
}
?>
So at the moment what is happening is it is just echoing the address they input, no conversion happens.
I don't know (or care) when the conversion should happen, e.g. whether it should happen before submission or after.
Thanks for any feedback!
I made a basic example of how it could work, please see the JSFiddle here: http://jsfiddle.net/5mMtm/1/
The principle is:
capture the form's submit
do an ajax call to an API (in your case geocoder) with the data entered
change form input value and send/submit to own endpoint
I'm using jQuery in the example:
$(function(){
var $form = $('#my-form'), // the form
$adrInput = $form.find('[name=address]'), // the address input field
isSearching = false; // a flag to prevent multiple submits
// on form submit event
$form.on('submit', function(e){
// Prevent submit event
e.preventDefault();
// Don't start another search while
// other is still going
if( isSearching ){ return; }
isSearching = true;
// Start query to google
getAddressFromGoogle();
});
function getAddressFromGoogle(){
var address = $adrInput.val();
// Get lat/lng value and then do something with it
getLatLng( address, function( lat, lng ){
$adrInput.val( lat + ',' + lng );
});
}
// this function takes two parameters
// the address as a string from the input field
// and a callback it will invoke with the results
// when it's done
function getLatLng( address, callback ){
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'address': address }, function( results, status ){
if( status == google.maps.GeocoderStatus.OK ){
// Get the Lat. and Long.
var lat = results[0].geometry.location.lat(),
lng = results[0].geometry.location.lng();
// Pass latLng to callback function
if( typeof callback === 'function' ){
callback.apply( null, [ lat, lng ]);
}
}
else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
});
You have to do an event.preventDefault() at the begining. It will prevent the submit made by the "browser" ... so you will be able to do your own submit.
Here is a simplified version of your code:
Javascript:
var convertToCoords = function() {
event.preventDefault();
document.getElementById('address').value = "test";
document.getElementById('searchbar').submit();
};
Html:
<form name="searchform" action="required/results.php" method="get" id="searchbar" onsubmit="convertToCoords()">
<input type="text" name="input" id="address" placeholder="Search an address or suburb...">
<input type="submit" class="searchbtn" value="Search">
</form>
For a website where a user enters his address, I'm trying to find the location closest to him where the user can collect the ordered goods.
Based on the user's address I can narrow down the possible pick up locations to between 2 and 5. So I'd like to calculate the distance between user's address (point A) and the possible pick up locations.
The demo here works fine with just two addresses. I've adapted the code as much as I can to work with more than two addresses. I posted my JS code here since I can't seem to properly format it in SO.
In the code are two alerts. The first alert correctly shows the different pick up locations. But the second alert always shows the LAST pickup location.
Can anyone explain why?
HTML:
<p id="hello">Hello World</p>
JavaScript:
var geocoder, location1, location2, gDir;
function initialize(counter) {
if( counter == 0 ){
geocoder = new GClientGeocoder();
gDir = new GDirections();
}
GEvent.addListener(gDir, "load", function() {
var drivingDistanceMiles = gDir.getDistance().meters / 1609.344;
var drivingDistanceKilometers = gDir.getDistance().meters / 1000;
$("#results").append('<strong>Driving Distance: </strong>' + drivingDistanceKilometers + ' kilometers<br /><br />');
});
}
function getDistance(agency_add, counter) {
initialize(counter);
geocoder.getLocations(agency_add, function (response) {
if (!response || response.Status.code != 200) {
alert("Sorry, we were unable to geocode the address" + agency_add);
}
else {
location1 = {lat: response.Placemark[0].Point.coordinates[1], lon: response.Placemark[0].Point.coordinates[0], address: response.Placemark[0].address};
//alert("ONE: "+location1.address);
geocoder.getLocations(document.forms[0].address1.value, function (response) {
//alert("TWO: "+location1.address);
if (!response || response.Status.code != 200) {alert("Sorry, we were unable to geocode the second address");}
else {
location2 = {lat: response.Placemark[0].Point.coordinates[1], lon: response.Placemark[0].Point.coordinates[0], address: response.Placemark[0].address};
gDir.load('from: ' + location1.address + ' to: ' + location2.address);
}
});
}
});
}
$(document).ready(function(){
//put each agency address in an array
var agencies = [];
$(".agency_field").each(function(index) {
agencies.push($(this).val());
});
for (var i = 0; i < agencies.length; i++){
var res = getDistance(agencies[i], i);
}
});
you are calling geocoder.getLocations inside a loop. geocoder.getLocations runs asynchronously. when it receives the 2nd request while still processing the first, it cancels the first request.
If you want to multi-thread geocoder.getLocations you need to create multiple instances of it.