Overall Picture:
I want to add geocoding to my application. I was able to get it working in straight up JavaScript, but the callbacks are not getting triggered after converting to Angular/TypeScript.
Example: if a user enters 1 Microsoft Way, Redmond, WA. The longitude and latitude should be returned: latitude: 47.64006815850735, longitude: -122.12985791265965
Code examples are built off the following resources:
Bing Maps Ajax API - get location from address
https://msdn.microsoft.com/en-us/library/hh868062.aspx
Error Details:
The errors are occurring specifically within the variable name: geocodeRequest. searchModuleLoaded() gets loaded, but my geocodeRequest never triggers geocodeCallback or errCallback. I'm thinking it has something to do with the scope of my methods, but can't seem to isolate what is causing the error. Any ideas on how to get my callbacks to trigger?
Angular/TypeScript (Not Working)
$onInit() {
this.getMap();
}
getMap() {
this.map = new Microsoft.Maps.Map(document.getElementById('myMap'), {credentials: "your key here"});
Microsoft.Maps.loadModule('Microsoft.Maps.Search', { callback: this.searchModuleLoaded });
};
searchModuleLoaded() {
var searchManager = new Microsoft.Maps.Search.SearchManager(this.map);
var geocodeRequest = {
where: "1 Microsoft Way, Redmond, WA",
count: 10,
callback: this.geocodeCallback,
errorCallback: this.errCallback
};
searchManager.geocode(geocodeRequest);
}
geocodeCallback(geocodeResult, userData) {
// this callback never gets triggered
alert("The first geocode result is " + geocodeResult.results[0].location + ".");
}
errCallback(geocodeRequest) {
// this callback never gets triggered
alert("An error occurred.");
}
Working Version (Works, but no Angular/TypeScript)
function GetMap(){
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), {credentials: "key goes here", center: new Microsoft.Maps.Location(47.5, -122.3), zoom: 9 });
Microsoft.Maps.loadModule('Microsoft.Maps.Search', { callback: searchModuleLoaded });
}
function searchModuleLoaded(){
var searchManager = new Microsoft.Maps.Search.SearchManager(map);
var geocodeRequest = {where:"1 Microsoft Way, Redmond, WA", count:10, callback:geocodeCallback, errorCallback:errCallback};
searchManager.geocode(geocodeRequest);
debugger;
}
function geocodeCallback(geocodeResult, userData){
alert("The first geocode result is " + geocodeResult.results[0].location + ".");
}
function errCallback(geocodeRequest){
alert("An error occurred.");
}
After furthing investigation, I was able to resolve my issue.
What was the problem?
The issue was occurring within the searchModuleLoaded. Both callbacks were undefined. One issue is that it was trying to execute searchModuleLoaded before the module had loaded and another issue was caused because it didn't know the context of this.
To fix the issue, I had to modify the callback while loading Microsoft.Maps.Search. The module's callback is now converted to a lambda function, which calls this.searchModuleLoaded(). Once this gets compiled into JavaScript, it sets the this context appropriatly i.e _this = this. My code looks like this now:
getMap() {
this.map = new Microsoft.Maps.Map(document.getElementById('myMap'), {credentials: "put your key here"});
Microsoft.Maps.loadModule('Microsoft.Maps.Search', {
callback: () => {
this.searchModuleLoaded();
}
});
};
searchModuleLoaded() {
var searchManager = new Microsoft.Maps.Search.SearchManager(this.map);
var geocodeRequest = {
where: "1 Microsoft Way, Redmond, WA",
count: 10,
callback: this.geocodeCallback,
errorCallback: this.errCallback
};
searchManager.geocode(geocodeRequest);
};
geocodeCallback(geocodeResult, userData) {
alert("The first geocode result is " + geocodeResult.results[0].location + ".");
};
errCallback(geocodeRequest) {
alert("An error occurred.");
};
Related
I created a custom teams application using Microsoft Teams Toolkit for VS Code. I am trying to read the location from the app. I am able to load the coordinates in the Browser and Android version of teams but it fails in the Desktop version of teams with the below error.
Network location provider at 'https://www.googleapis.com/' : No response received.
The function to load the Location-
const getLocation = () => {
let that = this;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
alert('got position');
var positionInfo = "Your current position is (Latitude: " + position.coords.latitude + ", Longitude: " + position.coords.longitude + ")";
alert(positionInfo);
}, (error) => {
alert("Error: " + error.message);
}, { timeout: 30000, enableHighAccuracy: true, maximumAge: 75000 });
} else {
alert("Geolocation is not supported by this browser.");
}
}
It might be a problem with the navigator.geolocation().getCurrentPosition API. Any leads on this will be useful.
I will let this question be here for anyone looking for an answer or if anyone finds an update to this.
I found this official documentation from MSFT that states geolocation API is not fully supported in the teams desktop client currently and they suggest using the getLocation API of TeamsSDK.
https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/device-capabilities/native-device-permissions?tabs=desktop
I an using javascript and am getting an message that I have exceeded my daily request quota for this API. Is there a way to capture this error message in a try catch block so when I go over my quota I can execute another piece of code. I have seen several similar posts, but nothing that has been helpful. Here is my code.
(function (window, google, lat, lng) {
var options = {
center: {
lat: Number(lat),
lng: Number(lng)
},
zoom: 5,
disableDefaultUI: true,
scrollwheel: true,
draggable: false
},
element = document.getElementById('map-canvas')
var map = new google.maps.Map(element, options)
}(window, window.google, result[i]['latitude'], result[i]['longitude']));
Update
As per the documentation:
if you want to programmatically detect an authentication failure (for example to automatically send an beacon) you can prepare a callback function. If the following global function is defined it will be called when the authentication fails. function gm_authFailure() {//code}
Here is a list of errors that the gm_authFaliure function should be able to catch. It also mentions a OverQuotaMapError error.
As per the documentation:
if too many requests are made within a certain time period, the API returns an OVER_QUERY_LIMIT response code.
So you should check the response code. If the Google maps javascript library does not allow to access to the response code then I recommend making a HTTP request to the API to get the response code.
function initMap(window, google, lat, lng) {
var options = {
center: {
lat: Number(lat),
lng: Number(lng)
},
zoom: 5,
disableDefaultUI: true,
scrollwheel: true,
draggable: false
},
element = document.getElementById('map-canvas'),
map = new google.maps.Map(element, options);
};
function googleMapsCustomError(){
alert('Google Maps custom error triggered');
}
// if you want to respond to a specific error, you may hack the
// console to intercept messages.
// check if a message is a Google Map's error message and respond
// accordingly
(function takeOverConsole() { // taken from http://tobyho.com/2012/07/27/taking-over-console-log/
var console = window.console
if (!console) return
function intercept(method) {
var original = console[method]
console[method] = function() {
// check message
if(arguments[0] && arguments[0].indexOf('OverQuotaMapError') !== -1) {
googleMapsCustomError();
}
if (original.apply) {
// Do this for normal browsers
original.apply(console, arguments)
} else {
// Do this for IE
var message = Array.prototype.slice.apply(arguments).join(' ')
original(message)
}
}
}
var methods = ['error']; // only interested in the console.error method
for (var i = 0; i < methods.length; i++)
intercept(methods[i])
}())
<!DOCTYPE html>
<div id="map-canvas"></div>
<script>
// Notice i am defining this within my html file, just to be sure that this function exists before the Google Maps API is loaded.
window.gm_authFailure = function() {
// remove the map div or maybe call another API to load map
// maybe display a useful message to the user
alert('Google maps failed to load!');
}
window.showMap = function() {
var lat = -34.397,
lng = 150.644;
initMap(window, window.google, lat, lng);
};
</script>
<!-- We are passing an invalid API key. Also notice that we have defined 'callback' as 'showMap' which means that when the Google API JavaScript library is finished loading it will call the 'showMap' function. -->
<script src="https://maps.googleapis.com/maps/api/js?key=INVALID_API_KEY&callback=showMap"
async defer></script>
Yes, JavaScript supports try-catch blocks. Here is a sample implementation for your code:
(function (window, google, lat, lng) {
var options = {
center: {
lat: Number(lat),
lng: Number(lng)
},
zoom: 5,
disableDefaultUI: true,
scrollwheel: true,
draggable: false
},
element = document.getElementById('map-canvas')
try {
var map = new google.maps.Map(element, options)
} catch (error) {
// handle error
console.log(error.message);
} finally {
// optional cleanup code
}
}(window, window.google, result[i]['latitude'], result[i]['longitude']));
As per google documentation.
If you exceed the usage limits you will get an OVER_QUERY_LIMIT status
code as a response.
This means that the web service will stop providing normal responses
and switch to returning only status code OVER_QUERY_LIMIT until more
usage is allowed again. This can happen:
Within a few seconds, if the error was received because your application sent too many requests per second.
Within the next 24 hours, if the error was received because your application sent too many requests per day. The daily quotas are
reset at midnight, Pacific Time.
Please refer this link. It would be helpful.
I am working on an async.waterfall that I am unsure of how to avoid: "TypeError: Cannot read property 'MediaUrl' of undefined". This TypeError doesn't occur each time the script is run.
The flow is as follows:
getName (randomly chooses a name from a list of names
searchImage (uses the Bing search API to search photographs associated with that name
processBotdata (takes the results from Bing and randomly chooses one of the search results)
Step 3 is where the issue occurs:
function processBotdata (searchData, callback) {
var photographer = searchData.photographer // the search name
var array = searchData.array; // search results from bing
var randomIndex = Math.floor(Math.random() * array.length);
var mediaUrl = array[randomIndex].MediaUrl; // TypeError here!
var sourceUrl = array[randomIndex].SourceUrl;
var searchData = {
photographer,
mediaUrl,
sourceUrl
};
fs.readFile('results.json', function (err, data) {
var json = JSON.parse(data);
json.push(['search results for ' + photographer + ': ',
'mediaUrl: ' + searchData.mediaUrl,
'sourceUrl: ' + searchData.sourceUrl]);
fs.writeFile("results.json", JSON.stringify(json, null, "\t"));
console.log(' ==========> searchData appended to results.json file...')
});
console.log(' ==========> searchData has now been processed for upcoming tweet...');
setTimeout(function() {
callback(null, searchData);
console.log(searchData);
}, 5000);
}
I implemented a setTimeout for this function hoping that would resolve the issue. My thinking was that the Bing results searchData.array was not yet available to be processed, i.e. randomized and selected in this function. As I am new to Node.js and JavaScript I am unsure of my programming error here. I saw this post and I am wondering if it is related to the Bing Search Array which returns the top 50 results.
Update: here is how the async.waterfall is called:
async.waterfall([
getName,
async.retryable([opts = {times: 5, interval: 500}], searchImage),
async.retryable([opts = {times: 3, interval: 1000}], processBotdata),
async.retryable([opts = {times: 3, interval: 500}], getImage)
],
function(error, result) {
if (error) {
console.error(error);
return;
}
});
The most obvious possibility is that there is no object at the array index that you're getting. Since you're going after a random index, it makes sense that some random numbers are hitting populated indices, others are not. Is there any chance that the array is sparse or that the random number you're generating is out of range despite your attempts with Math.floor?
I'd check first in any case, something like:
var obj = array[randomIndex];
if(obj){
// do your stuff
}
/*** EDIT FOR NEW INFO ****/
Based on the comment, there's a chance that the Bing results will be an empty array, so the first thing you want to do is to test if that's the case and 'fail fast' to let async.retryable know it should retry:
function processBotData(searchData, callback){
if(!searchData || !searchData.array || !searchData.array.length)
return callback(new Error('No search results'));
// continue as before from here
}
Note that some folks would prefer my last condition to be something like searchData.array.length > 0, but 0 evals as false so I do it this way.
I'm using Tizen's Wearable SDK to create a watch face, and while I am able to retrieve the Bluetooth's power state by using blueAdapter = tizen.bluetooth.getDefaultAdapter(); and bluetoothPowered = blueAdapter.powered;, I'd rather use a Bluetooth listener instead of constantly calling blueAdapter.powered.
The problem I'm having is that although I did a straight forward copy and paste of the sample code (although I did change the adapter's name, see below) from Tizen's Bluetooth API webpage, I'm getting the following error: 'undefined' is not a function (evaluating 'blueAdapter.setChangeListener(changeListener)').
This is the code I am using:
var blueAdapter = tizen.bluetooth.getDefaultAdapter();
var changeListener = {
onstatechanged: function(powered) {
console.log ("Power state is changed into: " + powered);
},
onnamechanged: function( name) {
console.log("Name is changed to: " + name);
},
onvisibilitychanged: function(visible) {
console.log("Visibility is changed into: " + visible);
}
};
blueAdapter.setChangeListener(changeListener);
Not sure if it helps, but I am using the following the privileges:
http://tizen.org/privilege/bluetooth.admin
http://tizen.org/privilege/bluetooth.gap
Any help would be appreciated.
Although it's been a while now, have you tried changing the syntax like below?
function changeListener(handler) {
handler.onstatechanged = function(powered) {
console.log ("Power state is changed into: " + powered);
}
handler.onnamechanged = function(name) {
console.log("Name is changed to: " + name);
}
handler.onvisibilitychanged = function(visible) {
console.log("Visibility is changed into: " + visible);
}
};
this replaces your listener object by a function, which should then declare the needed functions in the listener. It is just an idea, i did not test it yet.
I'm really new to Javascript, and I'm trying to jump into it.
I want to have a script get geolocation data and pass it to a variable, and then have the information displayed in an alert.
I have a jsFiddle here: http://jsfiddle.net/yJrtR/
When I run it, I get an "undefined" in the alert box. Can someone help me with this?
Here is my code:
function lat() {
navigator.geolocation.getCurrentPosition(function (position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;
}, function (error) {
console.log("Something went wrong: ", error);
});
}
function alert() {
var lat="";
var lon="";
lat();
alert("lat + lon");
}
There are several weird things in your code. Your fiddle is set to run onLoad, which means the functions you defined in your JavaScript won't be available globally - they'll be defined in the window.onload handler...which doesn't code outside of that to access them (especially inline event handlers). This is a perfect example of why not to use inline event handlers (even though the problem is really because of the jsFiddle settings).
So that means, when you call alert(); in your button's inline click handler, it calls the native window.alert() function, which brings up a dialog window. Since you pass nothing to it, it shows undefined. It's not actually calling your created alert function.
Also, since the getCurrentPosition method seems to be asynchronous, you should pass a callback function to lat, so that you can call it when it gets position.
Try this:
function lat(callback) {
navigator.geolocation.getCurrentPosition(function (position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;
callback.call(null, lat, lon);
}, function (error) {
console.log("Something went wrong: ", error);
});
}
function getPosition() {
lat(function (latitude, longitude) {
alert("lat: " + latitude + ", lon: " + longitude);
});
}
http://jsfiddle.net/yJrtR/1/
UPDATE:
Per your comment, if you'd like it to be shown "live", you can use something like this:
window.onload = function () {
var latElement = document.getElementById("lat"),
lonElement = document.getElementById("lon"),
lastUpdatedElement = document.getElementById("last_updated"),
getPositionOptions = {
enableHighAccuracy: false,
timeout: 10000,
maximumAge: 0
},
getPos = function () {
console.log("getPos function called");
navigator.geolocation.getCurrentPosition(function (position) {
console.log("Successfully retrieved position: ", position);
var coords = position.coords;
latElement.innerHTML = coords.latitude;
lonElement.innerHTML = coords.longitude;
lastUpdatedElement.innerHTML = new Date(position.timestamp);
setTimeout(getPos, 5000);
}, function (error) {
console.log("Something went wrong retrieving position: ", error);
setTimeout(getPos, 5000);
}, getPositionOptions);
};
getPos();
};
with the following HTML (just to "simulate" the dialog you speak of):
<div id="dialog">
<div>Your latitude is: <span id="lat"></span></div>
<div>Your longitude is: <span id="lon"></span></div>
<div>Last Updated: <small id="last_updated"></small></div>
</div>
DEMO: http://jsfiddle.net/yJrtR/12/
So what this code does is from the time the window has loaded, it continually re-gets the geo position. There are special options you can pass to the getCurrentPosition, that I declared in getPositionOptions.
As I said before, the getCurrentPosition is asynchronous, so the position could be retrieved at any time after calling getCurrentPosition is called...that's what the callbacks are for. In the options object, I set a timeout - 10000 - that says "don't take any longer than 10 seconds to retrieve the position", and if it does, it will call the error callback. The maximumAge option makes sure it always tries to grab the current location (instead of using a cached version, within a certain period of time.
So when either callback is called (could be 1 second later, could be 20 seconds later...although we set a timeout of 10 seconds), it will update the HTML with the details, and then do it all again 5 seconds later - that's what the setTimeout is for. This is because if we continually tried to get the position (without any kind of delay), the page would be very busy getting the position. 5 second delays, or even up to 15, should be fine.
Reference:
https://developer.mozilla.org/en-US/docs/DOM/window.navigator.geolocation.getCurrentPosition
UPDATE:
There is a specific method for the geolocation feature that lets you watch the position, called watchPosition, doing exactly what I was trying to emulate, but more efficiently. You could try this:
window.onload = function () {
var latElement = document.getElementById("lat"),
lonElement = document.getElementById("lon"),
lastUpdatedElement = document.getElementById("last_updated"),
watchPositionOptions = {
enableHighAccuracy: false,
timeout: 10000,
maximumAge: 0
};
navigator.geolocation.watchPosition(function (position) {
console.log("Successfully retrieved position: ", position);
var coords = position.coords;
latElement.innerHTML = coords.latitude;
lonElement.innerHTML = coords.longitude;
lastUpdatedElement.innerHTML = new Date(position.timestamp);
}, function (error) {
console.log("Something went wrong retrieving position: ", error);
}, watchPositionOptions);
};
DEMO: http://jsfiddle.net/yJrtR/14/
Reference:
https://developer.mozilla.org/en-US/docs/DOM/window.navigator.geolocation.watchPosition?redirect=no