how can I get latitude and longitude outside created object?
I've made new object of Ext.util.Geolocation, updated it, and now I'm trying to get Latitude and Longitude values outside the object, but it shows me 'null'.
Code:
var geo = Ext.create('Ext.util.Geolocation', {
autoUpdate: false,
listeners: {
locationupdate: function(geo) {
//alert('New latitude: ' + geo.getLatitude());
},
locationerror: function(geo, bTimeout, bPermissionDenied, bLocationUnavailable, message) {
if(bTimeout){
alert('Timeout occurred.');
} else {
alert('Error occurred.');
}
}
}
});
geo.updateLocation();
//geo.fireEvent('locationupdate');
alert(geo.getLatitude()); // it shows null
Thanks in advance.
It's probably because it takes some time to get your location.
You should try to get the latitude and the longitude within the locationupdate callback function.
If you want to access it outside, just make sure that geo exists
if (geo) { alert(geo.getLatitude()); }
Hope this helps
This is just a timing issue - obtaining the location is not synchronous, therefore you can not access it outside the locationupdate callback function, at least until it has been initialized.
You should do whatever you need to do inside that callback (e.g. call another function passing in the latitude if it needs)...
...
listeners: {
locationupdate: function(geo) {
yourCallbackFunction(geo.getLatitude());
},
...
If you really need to use it outside that callback, then in the worst case you can do something like:
var latitude; //will store latitude when ready..
var geo = Ext.create('Ext.util.Geolocation', {
autoUpdate: false,
listeners: {
locationupdate: function(geo) {
latitude = geo.getLatitude();
}
}
});
geo.updateLocation();
//waits until latitude exists then does something..
var untilLatThere = setInterval(function(){
if(latitude) {
alert(latitude); //alerts a valid value..
clearInterval(untilLatThere);
}
}, 100);
Related
I am working on a pothole map, and am on the stage where I load pothole data from the server and put it on the map as markers. Since data retrieval and the APIs that my app relies on (Roads, Geolocation, etc.) are asynchronous, my code ended up refactored to run asynchronously. I refactored the code blocks that added the markers to the map to this:
/* put all potholes on the map
* Parameters:
* • callback : the function to call next
*/
function addPotholeMarkers(callback)
{
var DEBUG = false;
// guarantee that callback is function
if ((callback) && (typeof(callback) !== 'function')) throw new TypeError('callback is something, but not a function. Thrown from addPotholeMarkers().');
// add all the markers for them to the map
async.waterfall([
function(cb) {
async.eachOf(potholeAddresses, function(value, key) {
async.eachOf(value, function (v, k) {
addPotholeMarker(v, false);
})
})
if (cb && typeof cb === 'function') cb(null);
}, function(cb) {
async.eachOf(potholeCoordinates, function(value, key) {
async.eachOf(value, function(v, k) {
async.setImmediate(function() { addPotholeMarker(v); }); // This came from
})
})
}], function(err, results) {
console.log('trying to center map');
reCenterMap();
console.log('Map recentered');
if (callback) {
callback(err);
}
});
}
and addPotholeMarker() looks something like:
/* code was initially obtained from https://developers.google.com/maps/documentation/roads/inspector */
/* Adds marker to map.
* Parameters :
* • potholeData : a PotholeData (or PotholeDataFromCoords) object
* • snappedToRoad: boolean
* Returns :
* • the marker that was added to the map, or null if arguments invalid
*/
function addPotholeMarker(potholeData, snappedToRoad) {
// make sure potholeState is either falsy or contains iconURL string
if ((!potholeData.potholeState) || ((potholeData.potholeState) && (potholeData.potholeState.iconURL === undefined))) throw new Error('invalid potholeData');
// let's make sure to snap this to road if it isn't already...
var coords = new GPSCoordinates(potholeData.lat, potholeData.lng);
if (!snappedToRoad)
{
var potholeMarker = 'a garbage return value';
getRoadCoordinates(coords).done(function(response) {
var coords = response.snappedPoints[0].location;
potholeData.lat = coords.latitude;
potholeData.lng = coords.longitude;
return (potholeMarker = addPotholeMarker(potholeData, true));
/* potholeMarker = addPotholeMarker(potholeData, true);
return potholeMarker;*/
});
return;
//return potholeMarker;
}
var marker = new google.maps.Marker({
position: coords,
title: coords.toString(),
map: map,
opacity: 0.5,
icon: ((potholeData.potholeState.iconURL !== undefined) ? potholeData.potholeState.iconURL : PURPLE_MARKER)
});
// make marker have effect when mouseout,mouseover
marker.addListener('mouseover', function(mouseEvent) {
marker.setOpacity(1.0);
});
marker.addListener('mouseout', function(mouseEvent) {
marker.setOpacity(0.5);
});
var infoWindow = createInfoWindow(potholeData);
// save infoWindow for later reference
infoWindows[statesMap.get(getPotholeStateFor(potholeData.potholeState))].push(infoWindow);
// on click of marker, show infoWindow
marker.addListener('click', function(mouseEvent) {
infoWindow.open(map, marker);
});
// add this to potholeMarkers
potholeMarkers[statesMap.get(getPotholeStateFor(potholeData.potholeState))].push(marker);
return marker;
}
This app is hosted on Google Apps Script (you'll need Google account to run this), and uses the client-side async library
This code, when ran successfully, is supposed to re-center the map at the position-average of all the markers. reCenterMap() works as it should, so I omitted it in attempt at MVCE.
When I ran the code
During any tick of the asynchronous loop, the members of the potholeCoordinates object (which is an Object<Array<PotholeData> >) appear empty. How to fix this?
After showing a friend this problem, contemplating his advice on this, and staying up last night for a few hours to work on it myself, I made the following changes:
not related to this problem, but
I changed the index statesMap.get(getPotholeStateFor(potholeData.potholeState)) to statesMap.get(getPotholeStateFor(potholeData)). Turns out that I gave getPotholeStateFor() the wrong object, which made it return the wrong state.
I changed the signature of addPotholeMarker(potholeData, snappedToRoad) to addPotholeMarker(potholeData, snappedToRoad, callback); /* because apparently I forgot that, with async functions, callbacks must be passed to the lowest level functions and invoked there, with signature callback(err, results) or something similar */
Inside addPotholeMarker() I made sure to use callback, but in a modular way:
if (callback) return callback(null, potholeMarker);
return potholeMarker;
/* I applied this change to the if (!snappedToRoad), but that if-statement is still broken: it will return before it finishes its task of appending to array, and return callback(null, potholeMarker) will cause the callback to be invoked twice. I may end up having to refactor this whole function, especially to append to potholeMarkers (which, btw, is global) after this function (it will be the callback to this) */
The innermost async loop in addPotholeMarkers() got changed from :
async.eachOf(value, function(v, k) {
async.setImmediate(function() { addPotholeMarker(v); });
})
to
async.eachSeries(value, function(pothole, fn) {
addPotholeMarker(pothole,
true,
//pothole.isSnappedToRoad(),
fn);
})
NOTE pothole.isSnappedToRoad() is commented out because it returns false, and addPotholeMarker() doesn't work right in the main call stack with the second parameter false. Also, it should return true, but it isn't because this type of error happened in function prior to addPotholeMarkers(); /* I'm going to fix that next! */
I'm working on a little web application which uses GPS. It uses Javascript to accomplish this. What I'm doing:
Defining an global array "positionCoords" with 2 empty indexes
(latitude / longitude).
On document ready, I am requesting latitude / longitude with the function "getGeoLocation()".
After the request, I am doing an simple console.log of the array. The array indexes are still empty.
Executing console.log(positionCoords) in the webbrowser console, gives me the correct values.
Could this has something to do with asynchronously? I'm quite new to this feature, any help would be appreciated!
// global variables
var positionCoords = {};
positionCoords['latitude'] = null;
positionCoords['longitude'] = null;
/*
on document ready, excecute
*/
$(document).ready(function() {
getGeolocation();
console.log(positionCoords);
});
/*
check if geolocation is supported and allowed, get coordinates
*/
function getGeolocation() {
if (navigator.geolocation) {
// geolocation is available
navigator.geolocation.getCurrentPosition(
function(position) {
// get coordinates
positionCoords['latitude'] = position.coords.latitude;
positionCoords['longitude'] = position.coords.longitude;
return true;
},
function(error){
handleGeolocationErrors(error);
return false;
}
);
} else {
// geolocation is not available
console.log("Browser does not support geolocation services.");
return false;
}
}
DEMO with Google Map
Since it is ASYNC call, you need to pass function-callback to getGeolocation, then , you will call it like the follwong :
ON Calling :
$(document).ready(function() {
getGeolocation(function(coords){
console.log(coords);
//====The resof your code which dependent on `coords` SHALL be here
//......
},function(err){console.log(err)});
});
To be able to call it like the above , you need to modify the implementation of getGeolocation by passing it two parameters :
Function Callback onSuccess.
Function Callback onError
Implementation :
/*
check if geolocation is supported and allowed, get coordinates
*/
function getGeolocation(fnsuccess,fnerror) {
if (navigator.geolocation) {
// geolocation is available
navigator.geolocation.getCurrentPosition(
function(position) {
if(typeof fnsuccess==='function'){
fnsuccess.call(null,position.coords); //--Call CallBack On Success
}
},
function(error){
if(typeof fnerror ==='function'){
fnerror.call(null,error); //--Call CallBack On Error
}
}
);
} else {
// geolocation is not available
console.log("Browser does not support geolocation services.");
return false;
}
}
DEMO :
the DEMO will ask you to share your location , if you accept , check the console of your browser , you will get Coords as you expect
DEMO with Google Map
What I'm trying to do:
I need to request the user's location and save the latitude & longitude into an object. Since this may take some time, I need to occasionally check to see if the coordinates have been saved. I am using a setTimeout to check to see if the coordinates have been saved every 500ms. Once `
The problem:
checkCoords() runs once and returns "user coords doesn't exist", however it seems like it does not continue to run.
What would be the best way to make sure userGeometry is returned once the coordinates have been saved?
EXAMPLE.GetUserGeometry = function() {
console.log("Starting geolocation...");
var userGeometry = navigator.geolocation.getCurrentPosition(save_location);
function save_location(position) {
var user_coordinates = {
latitude: position.coords.latitude,
longitude: position.coords.longitude
};
console.log(user_coordinates);
return user_coordinates;
}
setTimeout(checkCoords(userGeometry), 500);
function checkCoords(coords) {
if (typeof coords === 'undefined') {
console.log("user coords don't exist");
} else {
console.log("user coords saved");
}
}
};
I have 2 js files, 1 is to store the location data in an object and the other is the event handler for the click events and such.
This works:
var Geology = {
coords: {},
error: '',
setPosition: function (position) {
Geology.coords = position.coords;
// DEBUG
for (var prop in Geology.coords)
console.log(prop + ': ' + Geology.coords[prop]);
},
setError: function (error) {
Geology.error = error;
}
};
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(Geology.setPosition,Geology.setError,{timeout:10000});
}
But i want to be able to update the location data if necessary by a click or timer. Any time i try to do that it doesn't assign the vars to Geology like it does initially.
like this:
jQuery(document).ready(function($){
$('.toggle').click(function(){
//- get geo location if available
if (typeof Geology === 'object') {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(Geology.setPosition,Geology.setError,{timeout:10000});
}
}
});
});
I don't get errors in the console but it just fails and does not run the callback. However, it does run the getCurrentPosition method because I've tested to see if it makes it through the conditionals.
I think you need to set the maximum_age parameter, otherwise the results will be cached forever :
navigator.geolocation.getCurrentPosition(
geo_success,
geo_error,
{ maximumAge:60000 } // set to 1min (in ms)
);
You also have two other parameters : enableHighAccuracy and timeout
More info: https://developer.mozilla.org/en-US/docs/Using_geolocation
EDIT : I just found this, it's probably related to your issue navigator.geolocation.getCurrentPosition sometimes works sometimes doesn't
I have a function that calls the geolocator and i don't know how to test this function. I've tried spying on the geolocator and returning fake data but with no success, the original function is still used and so i would have to wait and i couldn't use mock data.
// this doesn't work
var navigator_spy = spyOn( navigator.geolocation, 'getCurrentPosition' ).andReturn( {
coords : {
latitude : 63,
longitude : 143
}
} );
How can I do this?
When you call the geolocation code, it looks like this:
navigator.geolocation.getCurrentPosition(onSuccess, onError);
This means that you're calling it and passing it functions:
function onSuccess(position) {
// do something with the coordinates returned
var myLat = position.coords.latitude;
var myLon = position.coords.longitude;
}
function onError(error) {
// do something when an error occurs
}
So, if you wanted to spy on it using jasmine returning a value, you'd want call the success function using the first argument of the original call like this:
spyOn(navigator.geolocation,"getCurrentPosition").andCallFake(function() {
var position = { coords: { latitude: 32, longitude: -96 } };
arguments[0](position);
});
If you wanted to make it look like an error was returned, you'd want to call the error function using the second argument of the original call like this:
spyOn(navigator.geolocation,"getCurrentPosition").andCallFake(function() {
arguments[1](error);
});
Edit to show full example:
This is the function you are using Jasmine to test:
function GetZipcodeFromGeolocation(onSuccess, onError) {
navigator.geolocation.getCurrentPosition(function(position) {
// do something with the position info like call
// an web service with an ajax call to get data
var zipcode = CallWebServiceWithPosition(position);
onSuccess(zipcode);
}, function(error) {
onError(error);
});
}
This would be in your spec file:
describe("Get Zipcode From Geolocation", function() {
it("should execute the onSuccess function with valid data", function() {
var jasmineSuccess = jasmine.createSpy();
var jasmineError = jasmine.createSpy();
spyOn(navigator.geolocation,"getCurrentPosition").andCallFake(function() {
var position = { coords: { latitude: 32.8569, longitude: -96.9628 } };
arguments[0](position);
});
GetZipcodeFromGeolocation(jasmineSuccess, jasmineError);
waitsFor(jasmineSuccess.callCount > 0);
runs(function() {
expect(jasmineSuccess).wasCalledWith('75038');
});
});
});
At this point, when you run the spec, it will tell you that your web service gave you the proper zip code for the latitude and longitude you supplied if your web service works properly.
Ah wait, maybe you HAVE to create the spy within your beforeEach block because Jasmine restores spies automatically after each test case. if you did something like:
var navigator_spy = spyOn( navigator.geolocation, 'getCurrentPosition' )
it("should stub the navigator", function() {
// your test code
});
the spy is already restored when you want to test it. Use this instead:
beforeEach(function() {
this.navigatorSpy = spyOn( navigator.geolocation, 'getCurrentPosition' )
});
it("should work now since the spy is created in beforeEach", function() {
// test code
});