User shared GEOlocation does not work with google places - javascript

I don't know how to search for this in SO, so I'm asking a new question. What could cause or what is the concrete problem of my code: HTML generated by Javascript (createElement() and appendChild) is not being shown in Opera and Firefox, but it works in Chromium.
The HTML generating code:
function typesOfPlaces(map, bounds) {
var allowedTypes = [
"amusement_park",
"aquarium",
"art_gallery",
"cemetery",
"church",
"city_hall",
"hindu_temple",
"mosque",
"museum",
"night_club",
"park",
"place_of_worship",
"rv_park",
"spa",
"synagogue",
"travel_agency",
"zoo"
];
var typesToDisplay = new Array();
var request = {
bounds: bounds,
types: allowedTypes
};
var service = new google.maps.places.PlacesService(map);
service.nearbySearch(request, function(results, status) {
if(status == google.maps.places.PlacesServiceStatus.OK) {
for(var i = 0; i < results.length; i++) {
for(var j = 0; j < results[i].types.length; j++) {
for(var k = 0; k < allowedTypes.length; k++) {
if(results[i].types[j] == allowedTypes[k]) {
var allowed = true;
for(var x = 0; x < typesToDisplay.length; x++) {
if(allowedTypes[k]==typesToDisplay[x]) {
allowed = false;
}
}
if(allowed) {
typesToDisplay.push(allowedTypes[k]);
}
}
}
}
}
var parent = document.getElementById("types");
for(var i = 0; i < typesToDisplay.length; i++) {
var typeBox = document.createElement("div");
var checkBox = document.createElement("input");
var checkID = randomString(10);
var label = document.createElement("label");
checkBox.setAttribute("type", "checkbox");
checkBox.setAttribute("id", checkID);
label.setAttribute("for", checkID);
label.innerHTML = typesToDisplay[i];
typeBox.appendChild(checkBox);
typeBox.appendChild(label);
parent.appendChild(typeBox);
}
}
});
}//END OF Function
UPDATE TO COMMENTS
The randomString is just SO'ed code for generating random string:
function randomString(L) {
var s= '';
var randomchar=function() {
var n= Math.floor(Math.random()*62);
if(n<10) return n; //1-10
if(n<36) return String.fromCharCode(n+55); //A-Z
return String.fromCharCode(n+61); //a-z
}
while(s.length< L) s+= randomchar();
return s;
}
div #types really exists, it look like this:
<html>
<head>
...
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=MyKey&sensor=false&libraries=places&language=lt"></script>
</head>
<body>
<div>
<div>
<div id="types"></div>
</div>
</div>
</body>
</html>
You can see the import of google.maps.places.PlacesService by looking at the <head> section of the <script> tag, where you can see "&libraries=places".
SECOND UPDATE AFTER SOME TESTING
ok. I've figured out that if I deny location sharing in opera it works (it works in chromium because by default it does not even ask user if he is kind to share his geolocation with website)
The code for geolocation:
function initGeo()
{
if (navigator.geolocation)
{
navigator.geolocation.getCurrentPosition(successFunction, errorFunction);
}
else
{
errorFunction();
}
}
so, the function that does not work is successFunction (which is being launched if user kindly shares his geolocation)
function successFunction(position)
{
var geocoder = new google.maps.Geocoder();
var abstract_location;
var latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
geocoder.geocode({'latLng': latlng}, function(results, status)
{
if (status == google.maps.GeocoderStatus.OK)
{
abstract_location = new google.maps.LatLngBounds(
results[0].geometry.viewport.getSouthWest(),
results[0].geometry.viewport.getNorthEast());
}
else
{
alert("NOT SUCCESS 1");
}
showGMap(latlng, abstract_location);
});
}
And the errorFunction, which successfully works on chromium by default and on Opera if you deny access to your geolocation:
function errorFunction(error)
{
var geocoder = new google.maps.Geocoder();
if(google.loader.ClientLocation)
{
var latlng = new google.maps.LatLng(google.loader.ClientLocation.latitude, google.loader.ClientLocation.longitude);
geocoder.geocode({'latLng': latlng}, function(results, status)
{
if (status == google.maps.GeocoderStatus.OK)
{
var abstract_location = new google.maps.LatLngBounds(
results[0].geometry.viewport.getSouthWest(),
results[0].geometry.viewport.getNorthEast());
}
else
{
alert("NOT SUCCESS 2");
}
showGMap(latlng, abstract_location);
});
}
else
{
geocoder.geocode( {'address': 'Vilnius Region, Lithuania'}, function(results, status)
{
if (status == google.maps.GeocoderStatus.OK)
{
var latlng = results[0].geometry.location;
var abstract_location = new google.maps.LatLngBounds(
results[0].geometry.viewport.getSouthWest(),
results[0].geometry.viewport.getNorthEast());
showGMap(latlng, abstract_location);
}
else
{
alert("NOT SUCCESS 3");
}
});
}
}
Nor Chromium nor Opera does not give me ANY errors, nor javascript exceptionaly, nor in general.
So the problem is in success function. Because it even does not give me alert(typesToDisplay.length) [as suggested by Stuart in the comments] - it means that there is no alert at all - in case of error function I get the aswer 4 and thus i can see my generated HTML.
In case of success function there is just empty (without any appended childs) #types .
I do not see what could be causing success function to be NOTSUCCESS (:))

Ok, so i have figured it out - it was pretty simple though...
The Geolocation data which you get is an address, so bounds are very small, you have to extract city with reverse geocoding (results[6].formatted_address) and then you geocode that reverse geocode (so confused though Geocoding -> reverse -> again geocode) and then it works!
So the problem was at geocoding (haven't thought that bounds of address is not the whole city (that should have been obvious in the first place, but was not).
HTML5 geocoding could have the info about the city (not only lan and lng, firefox has something, but that's only firefox, not the whole HTML5), but i do not know if it would be good or not (lack of my personal knowlede at the moment in this specific field)
So if anyone does get to something similar -> check the bounds ;)
Thank you for your comments and for your view's.

Related

Knockout JS passing value into function

I have read many similar topics, but none of the answers seems to work for my case. I am working with Google Maps API to implement show/hide markers function using knockout data-binding. With show markers, there are no problems. But since I have to pass markers variable into hideMarkers function, I can't get this going.
Here is the html:
<div class="col-sm-6">
<input id="hide-listings" type="button" value="Hide Listings" class="btn1 btn-primary text-center" data-bind="click: hideMarkers">
</div>
Here is my ViewModel:
function viewModel() {
var self = this;
self.places = ko.observableArray(locations);
self.address = ko.observable();
self.city = ko.observable();
self.title = ko.observable();
self.id = ko.observable();
this.markers = ko.observable();
this.zaddress = ko.observable();
this.taddress = ko.observable();
this.paddress = ko.observable();
this.filter = ko.observable();
this.visiblePlaces = ko.computed(function() {
return this.places().filter(function(place) {
if (!self.filter() || place.title.toLowerCase().indexOf(self.filter().toLowerCase()) !== -1)
return place;
});
}, this);
//Zooms to a selected marker, open infowindow and displays current weather
self.zoomToPlace = function() {
// Initialize the geocoder.
var geocoder = new google.maps.Geocoder();
// Get the place.
var address = this.address;
var id = this.id;
var city = this.city;
var weatherAPIXU = "http://api.apixu.com/v1/current.json?key=453477e8eec14cbc805210143171706&q=" + city;
$.getJSON(weatherAPIXU, function(data) {
var forecast = data.current.temp_c;
$(".weather").html(forecast + '° C');
});
// Geocode the address/area entered to get the center. Then, center the map on it and zoom in
geocoder.geocode({
address: address,
}, function(results, status) {
map.setCenter(results[0].geometry.location);
map.setZoom(15);
google.maps.event.trigger(markers[id], 'click');
});
};
self.showListings = function() {
var bounds = new google.maps.LatLngBounds();
// Extend the boundaries of the map for each marker and display the marker
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
bounds.extend(markers[i].position);
}
map.fitBounds(bounds);
};
// This function takes the input value in the find nearby area text input
// locates it, and then zooms into that area. This is so that the user can
// show all listings, then decide to focus on one area of the map.
self.zoomToArea = function() {
// Initialize the geocoder.
var geocoder = new google.maps.Geocoder();
// Get the address or place that the user entered.
var zaddress = this.zaddress();
// Make sure the address isn't blank.
if (zaddress === '') {
window.alert('You must enter an area, or address.');
} else {
// Geocode the address/area entered to get the center. Then, center the map on it and zoom in
geocoder.geocode({
address: zaddress,
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
map.setZoom(15);
} else {
window.alert(
'We could not find that location - try entering a more' +
' specific place.');
}
});
}
};
// This function allows the user to input a desired travel time, in
// minutes, and a travel mode, and a location - and only show the listings
// that are within that travel time (via that travel mode) of the location
self.searchWithinTime = function() {
// Initialize the distance matrix service.
var distanceMatrixService = new google.maps.DistanceMatrixService();
var taddress = this.taddress();
// Check to make sure the place entered isn't blank.
if (taddress === '') {
window.alert('You must enter an address.');
} else {
hideMarkers(markers);
// Use the distance matrix service to calculate the duration of the
// routes between all our markers, and the destination address entered
// by the user. Then put all the origins into an origin matrix.
var origins = [];
for (var i = 0; i < markers.length; i++) {
origins[i] = markers[i].position;
}
var destination = taddress;
var mode = document.getElementById('mode').value;
// Now that both the origins and destination are defined, get all the
// info for the distances between them.
distanceMatrixService.getDistanceMatrix({
origins: origins,
destinations: [destination],
travelMode: google.maps.TravelMode[mode],
unitSystem: google.maps.UnitSystem.IMPERIAL,
}, function(response, status) {
if (status !== google.maps.DistanceMatrixStatus
.OK) {
window.alert('Error was: ' + status);
} else {
displayMarkersWithinTime(response);
}
});
}
};
// This function fires when the user select "go" on the places search.
// It will do a nearby search using the entered query string or place.
self.textSearchPlaces = function() {
var bounds = map.getBounds();
var place = this.paddress();
hideMarkers(placeMarkers);
var placesService = new google.maps.places.PlacesService(map);
placesService.textSearch({
query: place,
bounds: bounds
}, function(results, status) {
if (status === google.maps.places.PlacesServiceStatus
.OK) {
createMarkersForPlaces(results);
}
});
};
// This function will loop through the listings and hide them all.
this.hideMarkers = function(markers) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
};
}
ko.applyBindings(new viewModel());
Please, advice me on how to best approach this issue, thank you!
If markers is this.markers then you dont need to pass the markers to the function as its available:
this.hideMarkers = function(markers) {
var m = markers == null ? this.markers : markers;
for (var i = 0; i < m.length; i++) {
m[i].setMap(null);
}
};
This means you can pass markers also to this function and if you dont it will default to your this.markers.
You can pass extra parameters in knockout like this also, if that is all your looking:
<input data-bind="click: hideMarkers.bind($data, markersYouWishtoHide)">
http://knockoutjs.com/documentation/click-binding.html
I have figured it out! The problem was that I was passing the value into the function inside the viewModel, but not in my click data-binding! The correct html:
<div class="col-sm-6">
<input id="hide-listings" type="button" value="Hide Listings" class="btn1 btn-primary text-center" data-bind="click: function() {hideMarkers(markers)}">
</div>
And the ViewModel function is simply:
self.hideMarkers = function() {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
};

How to pass javascript alert message value to label in asp.net

I had implemented geolocation , wherein browser gets location of user.
In this code i'm getting geolocation of user through browser ,but it display location using javascript alert message.
I just want to pass alert message value to label or hiddenfield in ASP.Net & doesn't want to run alert message
My javascript code as follows.
<script type="text/javascript">
var geocoder;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(successFunction, errorFunction);
}
//Get the latitude and the longitude;
function successFunction(position) {
var lat = position.coords.latitude;
var lng = position.coords.longitude;
codeLatLng(lat, lng)
}
function errorFunction() {
alert("Geocoder failed");
}
function initialize() {
geocoder = new google.maps.Geocoder();
}
function codeLatLng(lat, lng) {
var latlng = new google.maps.LatLng(lat, lng);
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
console.log(results)
if (results[1]) {
//formatted address
alert(results[0].formatted_address)
//find country name
for (var i = 0; i < results[0].address_components.length; i++) {
for (var b = 0; b < results[0].address_components[i].types.length; b++) {
//there are different types that might hold a city admin_area_lvl_1 usually does in come cases looking for sublocality type will be more appropriate
if (results[0].address_components[i].types[b] == "administrative_area_level_1") {
//this is the object you are looking for
city = results[0].address_components[i];
break;
}
}
}
//city data
alert(city.short_name + " " + city.long_name)
document.getElementById('<%=Label1.ClientID %>').innerHTML = city;
} else {
alert("No results found");
}
} else {
alert("Geocoder failed due to: " + status);
}
});
}
</script>
If you want to store the value in a hidden field replace
alert(results[0].formatted_address)
with
//hdnField is the ID of your asp:HiddenField object
var hiddenField = document.getElementById("<%= hdnField.ClientID %>")
hiddenField.value = results[0].formatted_address;

change Google maps API language

I'm using Azure platform to develop a website.
I'm using in Google maps API to get my location.
The server side is written in C#
I want that Google return the answer in English and not in other language.
How can I do this?
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false" lang="en-us"></script>
<script type="text/javascript">
var geocoder;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(successFunction, errorFunction);
}
//Get the latitude and the longitude;
function successFunction(position) {
var lat = position.coords.latitude;
var lng = position.coords.longitude;
codeLatLng(lat, lng)
}
function errorFunction() {
alert("Geocoder failed");
}
function initialize() {
geocoder = new google.maps.Geocoder();
}
function codeLatLng(lat, lng) {
var latlng = new google.maps.LatLng(lat, lng);
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
console.log(results)
if (results[1]) {
//formatted address
//alert(results[0].formatted_address)
document.getElementById('<%= citylbl.ClientID %>').value = results[0].formatted_address;
//find country name
for (var i = 0; i < results[0].address_components.length; i++) {
for (var b = 0; b < results[0].address_components[i].types.length; b++) {
//there are different types that might hold a city admin_area_lvl_1 usually does in come cases looking for sublocality type will be more appropriate
if (results[0].address_components[i].types[b] == "administrative_area_level_1") {
//this is the object you are looking for
city = results[0].address_components[i];
break;
}
}
}
//city data
//alert(city.short_name+" " + city.long_name);
} else {
alert("No results found");
}
} else {
alert("Geocoder failed due to: " + status);
}
});
}
</script>
</head>
<body onload="initialize()">
<asp:HiddenField ID="citylbl" runat="server" />
</body>
You need to add a language parameter in you API request.
For example: https://maps.googleapis.com/maps/api/js?language=ja will return information in Japanese.
You can visit this page about Google Maps Language Localization.
Also, the list of supported languages.

How to get address from lat and lng?

I have two set of lat and lng.
I want both address and stored in some variable:
var geocoder = new google.maps.Geocoder();
for(var i=0; i<json_devices.length; i++)
{
var lat = json_devices[i].latitude;
var lng = json_devices[i].longitude;
console.log(lat);
console.log(lng);
var latlng = new google.maps.LatLng(lat,lng);
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
address=results[1].formatted_address;
} else {
alert('No results found');
}
} else {
alert('Geocoder failed due to: ' + status);
}
});
console.log(address);
}
In this, lat & lan get correctly. But address are not stored in variable. What is the mistake?
I am using this method and it is working perfect for me.
Please have a look on it.
public String getAddressFromLatLong(GeoPoint point) {
String address = "Address Not Found";
Geocoder geoCoder = new Geocoder(
getBaseContext(), Locale.getDefault());
try {
List<Address> addresses = geoCoder.getFromLocation(
point.getLatitudeE6() / 1E6,
point.getLongitudeE6() / 1E6, 1);
if (addresses.size() > 0) {
address =addresses.get(0).getAddressLine(0);
if(address.length()<=0)
address =addresses.get(0).getSubLocality();
}
}
catch (Exception e) {
e.printStackTrace();
}
return address;
}
Here the Google geocode is asynchonous type of function call.
From DOCS:
Accessing the Geocoding service is asynchronous, since the Google Maps
API needs to make a call to an external server. For that reason, you
need to pass a callback method to execute upon completion of the
request. This callback method processes the result(s). Note that the
geocoder may return more than one result.
So you can't get the address like that, instead use the common approach called callback.
Here I have created a sample code to explain the process, which can be altered by yourself.
var geocoder;
function codeLatLng(callback) {
geocoder = new google.maps.Geocoder();
var input = document.getElementById("latlng").value;
var latlngStr = input.split(",", 2);
var lat = parseFloat(latlngStr[0]);
var lng = parseFloat(latlngStr[1]);
var latlng = new google.maps.LatLng(lat, lng);
geocoder.geocode({
'latLng': latlng
}, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
address = results[1].formatted_address;
callback(address);
} else {
alert("No results found");
}
} else {
alert("Geocoder failed due to: " + status);
}
});
}
$('input[type="button"]').on('click', function () {
codeLatLng(function (address) { //function call with a callback
console.log(address); // THE ADDRESS WILL BE OBTAINED
})
});
JSFIDDLE

Why is my variable not being defined?

I have the following code:
function codeAddress(){
geocoder = new google.maps.Geocoder();
for (var i=1; i < 4; i++){
var sAddress =document.getElementById("search_postcode" + i).value ;
var loc=[];
geocoder.geocode({ 'address': sAddress}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK)
{
loc[0] = results[0].geometry.location.lat();
loc[1]=results[0].geometry.location.lng();
document.getElementById("geo_lat" + i).value = loc[0];
document.getElementById("geo_lon" + i).value = loc[1];
}
else
{
alert(status);
}
}); //end geocode function
} //end for
} //end codeAddress function
Can anybody see why the variable i isnt getting set? The code works fine if I replace the i's with a number, but in the javascript error console, i isnt being defined so var sAddress is NULL.
EDIT
The following code gives the correct answer when typed into the console when I put a breakpoint immediately after the defining of the 'for' loop:
Why would it not work in code but will work when manually typed into the console?
If the exact code works with i replaced with numbers as you say then it looks like the problem is that by the time your callback is called the captured i will be 4 (which if it doesn't cause your current issue will cause future issues)
Try this (copies i into a new scope):
function codeAddress(){
geocoder = new google.maps.Geocoder();
for (var i=1; i < 4; i++){
var sAddress =document.getElementById("search_postcode" + i).value ;
var loc=[];
geocoder.geocode({ 'address': sAddress}, (function(i){
return function(results, status) {
if (status == google.maps.GeocoderStatus.OK)
{
loc[0] = results[0].geometry.location.lat();
loc[1]=results[0].geometry.location.lng();
document.getElementById("geo_lat" + i).value = loc[0];
document.getElementById("geo_lon" + i).value = loc[1];
}
else
{
alert(status);
}
};
})(i)); //end geocode function
} //end for
} //end codeAddress function
Otherwise if document.getElementById("search_postcode" + i) is returning null in your function and not in the console then it probably means your code is running before the document has loaded
check whether perticular Id exists or not before invoking the getElementById method,

Categories