How to make jQuery constructor properties globally visible - javascript

I am trying to get position coordinate variables using the standard Navigator.geolocation property with jquery, so i can use the value later in my code:
$(document).ready(function(){
$.getlocation = function(){
navigator.geolocation.getCurrentPosition($.getPosition,$.error);
}
$.getVariables = function(lat,lon){
this.lat = lat; // i want these to be visible
this.lon = lon;
}
$.getPosition= function(position){
console.log("latitude:" +position.coords.latitude+ " longitude: "+position.coords.longitude);
//this function will be executed once position is determined.
$.getVariables(position.coords.latitude,position.coords.longitude);
}
$.error = function(){alert("error");}
$.getlocation(); // outputs correctly
setTimeout(()=>{console.log(this.lat)},5000); // undefined
});
I expect to get location output but instead i get undefined from console.log(this.lat), i did try this in vanilla javascript and it works fine, here is the javascript code:
function locateMe() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getPosition, error);
} else {
alert("connection problem");
}
}
let vars = function(lat, lon) {
this.lat = lat;
this.lon = lon;
}
let getPosition = function(position) {
vars(position.coords.latitude, position.coords.loongitude);
}
let error = function(msg) {
console.log("problem");
}
locateMe();
setTimeout(() => { console.log(this.lat); }, 5000); //correct output

I could get this.lat working if I changed getVariables to:
$.getVariables = function(lat,lon){
document.lat = lat;
document.lon = lon;
}
It appears that the two this objects may refer to different things in the two methods.

Related

geolocation keeps on asking for permission

I was testing geolocation API and found if I refresh my page, the page keeps on asking for permission, so I saved my coordinate data to local storage but it doesn't works! Is there any way to give permission only once???
const COORDINATION = "coords";
function saveCords(coordsOBJ){
localStorage.setItem(COORDINATION,JSON.stringify(coordsOBJ));
}
function handleGeoError(position){
console.log("Cant find position");
}
function handleGeoSuccess(position){
// console.log(position);
const latitude = position.coords.latitude;
console.log(latitude);
const longitude = position.coords.longitude;
const coordsOBJ = {
latitude,//latitude = latitude,
longitude//longitude = longitude
}
saveCords(coordsOBJ);
}
function askForCoords(){
navigator.geolocation.getCurrentPosition(handleGeoSuccess,handleGeoError);
}
function loadCoordinate(){
const loadedCords = localStorage.getItem("COORDINATION");
if(loadedCords === null)
{
askForCoords();
}
}
function init(){
loadCoordinate();
}
It looks like there is a typo in your code, whereby you've added quotes to COORDINATION but it's a varible not a string.
Try changing:
const loadedCords = localStorage.getItem("COORDINATION");
To:
const loadedCords = localStorage.getItem(COORDINATION);

"weather is not defined" error when working with openwethermap API

I'm somewhat new to working with API's using vanilla JavaScript and I keep running into this error when trying to access the "description" within the "weather object". The console keeps reading "weather is not defined". I'm using the open weather map API. In theory I should be able to retrieve using data.current.weather.description. but that doesn't work, along with the other variations I've tried. Here is my current code.
window.addEventListener("load", () => {
let long;
let lat;
let temperatureDescription = document.querySelector(
".temperature-description"
);
let temperatureDegree = document.querySelector(".temperature-degree");
let locationTimezone = document.querySelector(".location-timezone");
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
long = position.coords.longitude;
lat = position.coords.latitude;
const proxy = "https://cors-anywhere.herokuapp.com/";
const api = `${proxy}https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${long}&
exclude=hourly,daily&appid=da5463709c92ab1860d3a81037565c6e`;
fetch(api)
.then((response) => {
return response.json();
})
.then((data) => {
console.log(data);
const {
temp,
weather: { description },
} = data.current;
//Set DOM Elements from the API
let kelvinToCelsius = temp - 273.15;
temperatureDegree.textContent = kelvinToCelsius.toFixed(0);
temperatureDescription.textContent = description;
locationTimezone.textContent = data.timezone;
});
});
} else {
}
});
If anyone has ran into this issue and solved, it would be much appreciated if you filled me in.

Why can't $(document).ready() be inside API call?

FYI Trial 1 does not work, but Trial 2 works.
I understand that getJSON is executes asynchronously, but I don't actually understand how it applies to the code I've written.
What can I learn about asynchronous execution from this?
Why do I have to separate the getJSON call into a function separate from ready()?
FOR TRIAL 2:
How can I write this code so I don't have to initialize functions inside of getJSON? If there isn't a way, how can I write this code to be more robust?
/*
//TRIAL 1
$(document).ready(function(){
console.log("loaded");
$.getJSON(url, function(json){
var fahrenheit = true;
getLocation(json);
getTemperature(fahrenheit, json);
$("#unit").on("click", function(){
fahrenheit = !fahrenheit;
getTemperature(fahrenheit, json);
});
getWeather(json);
});
});
//Gets current weather conditions from current_observation
function getWeather(json){
var currWeather = "";
var iconURL = "";
currWeather=json.current_observation.weather;
iconURL=json.current_observation.icon_url;
$("#icon").attr("src", iconURL);
$("#weather").html(currWeather);
};
//Gets current temperature from current_observation
function getTemperature(fahrenheit, json){
var currTemp = 0;
if(fahrenheit){
currTemp+=json.current_observation.temp_f;
currTemp+="&#8457";
} else{
currTemp+=json.current_observation.temp_c;
currTemp+="&#8451";
}
$("#temperature").html(currTemp);
};
//Gets city, state, country, zip, latitude, and longitude from location
function getLocation(json){
var currLocation=["city", "state", "country", "zip", "lat", "lon"];
var locationHTML = "";
currLocation[0] = json.location.city;
currLocation[1] = json.location.state;
currLocation[2] = json.location.country_name;
currLocation[3] = json.location.zip;
currLocation[4] = json.location.lat;
currLocation[5] = json.location.lon;
locationHTML += currLocation[0]+", "+currLocation[1]+", "+currLocation[2]+" " +currLocation[3]+"<br>";
locationHTML += "Latitude: "+currLocation[4]+"<br>Longitude: "+currLocation[5];
$("#location").html(locationHTML);
};
*/
//TRIAL 2
$(document).ready(function(){
console.log("loaded");
dispWeather();
});
function dispWeather(){
console.log("inside dispWeather");
//Retrieve json from weather underground
var url = "https://api.wunderground.com/api/19c5c96f0b140c0f/geolookup/conditions/q/autoip.json";
$.getJSON(url, function(json){
console.log("Got JSON");
console.log(json);
var fahrenheit = true;
getLocation(json);
getTemperature(fahrenheit, json);
$("#unit").on("click", function(){
fahrenheit = !fahrenheit;
getTemperature(fahrenheit, json);
});
getWeather(json);
//Gets current weather conditions from current_observation
function getWeather(json){
var currWeather = "";
var iconURL = "";
currWeather=json.current_observation.weather;
iconURL=json.current_observation.icon_url;
$("#icon").attr("src", iconURL);
$("#weather").html(currWeather);
};
//Gets current temperature from current_observation
function getTemperature(fahrenheit, json){
var currTemp = 0;
if(fahrenheit){
currTemp+=json.current_observation.temp_f;
currTemp+="&#8457";
} else{
currTemp+=json.current_observation.temp_c;
currTemp+="&#8451";
}
$("#temperature").html(currTemp);
};
//Gets city, state, country, zip, latitude, and longitude from location
function getLocation(json){
var currLocation=["city", "state", "country", "zip", "lat", "lon"];
var locationHTML = "";
currLocation[0] = json.location.city;
currLocation[1] = json.location.state;
currLocation[2] = json.location.country_name;
currLocation[3] = json.location.zip;
currLocation[4] = json.location.lat;
currLocation[5] = json.location.lon;
locationHTML += currLocation[0]+", "+currLocation[1]+", "+currLocation[2]+" " +currLocation[3]+"<br>";
locationHTML += "Latitude: "+currLocation[4]+"<br>Longitude: "+currLocation[5];
$("#location").html(locationHTML);
};
})
};
.ready() jQuery Documentation
Specify a function to execute when the DOM is fully loaded.
What can I learn about asynchronous execution from this?
Your learning that you don't know when the document is going to be ready() so we wait until the event completes before beginning execution on our application. You also learned that you have to wait for $.getJSON to fetch json then you process the data.
Why do I have to separate the getJSON call into a function separate from ready()?
As specified above .ready() is waiting for the DOM to be fully loaded, then we start the application. So when we are "ready" lets fetch the weather data. The document is only ready one time when the DOM is fully loaded.
How can I write this code so I don't have to initialize functions inside of getJSON?
Without you being specific, I'm assuming your problem here was with toggling the degrees between celsius and fahrenheit. After we load the weather you can store the data in a variable outside of the scope of the function, this way when you click to change the degrees you can pass in the same data without having to call the api again (although at this point the weather could have changed)
how can I write this code to be more robust?
I've included a JS Bin that alters your code. The biggest problem was bad naming conventions and not keeping things simple. Example getWeather() was not "getting weather" it was setting html from data we got from $.getJSON which was invoked in your ready() instead of breaking it out into another function we could call later on.
For the most part this is how the code reads now, clear function names help quickly see what this code is supposed to do.
$(document).ready(function() {
renderWeather();
});
var state = {
fahrenheit: true,
data: {}
};
function renderWeather() {
getWeatherJSON()
.then(data => {
state.data = data;
setWeatherHTML(data);
setTemperatureHTML(data, state.fahrenheit);
setLocationHTML(data);
})
.catch(err => console.log(err));
}
http://jsbin.com/cekite/edit?js,output
If we wanted to take this a step further we could create a WeatherAPI prototype concealing our html render functions and extend it with a WeatherUndergroudAPI prototype, this way if we ever change our weather service we should only have to implement a format function to marshall the data the way the WeatherAPI expects it to be in.
class WeatherAPI {
constructor(opt) {
...
}
init() {
...
}
get() {
... feteches json from endpoint provided
}
renderWeather() {
this.get()
.then(this.formatter.bind(this))
.then(this.setWeatherData.bind(this))
.then(this.renderWeatherHTML.bind(this))
.then(this.renderTemperatureHTML.bind(this))
.then(this.renderLocationHTML.bind(this))
.catch(err => console.log(err));
}
formatter(data) {
...
}
setWeatherData(data) {
...
}
renderWeatherHTML() {
...
}
renderTemperatureHTML() {
...
}
renderLocationHTML() {
...
}
}
Extending the WeatherAPI is then a matter of passing in a new endpoint to get data from. Or in this case overriding the WeatherAPI get method and returning static data.
class FakeWeatherAPI extends WeatherAPI {
constructor(opt = {}) {
super(opt);
}
get() {
return new Promise((resolve) => {
const data = {
someReallyWeirdKeyForACity: 'San Francisco',
state: 'CA',
country: 'US',
lat: '37.77999878',
lon: '122.41999817',
f: '1000',
c: '25',
icon: 'http://www.nyan.cat/cats/zombie.gif',
weather: 'Acid Rain'
};
resolve(data);
});
}
formatter(data) {
const formattedData = {
city: data.someReallyWeirdKeyForACity,
state: data.state,
country: data.country,
lat: data.lat,
lon: data.lon,
temperature: {
fahrenheit: data.f,
celsius: data.c
},
icon: data.icon,
weather: data.weather
};
return formattedData;
}
}
Our application init code then becomes.
$(document).ready(init);
function init(){
const weatherAwesomeService = new FakeWeatherAPI();
weatherAwesomeService.init();
};
Here is a working jsbin for they above
http://jsbin.com/sicofe/edit?js,output

How do I get a value back from a custom dojo module?

I'm working through the process of modulization on an app that I have written. This works with spatial location
I'm using an event to query for the user's lat / lon position for use inside the application. My calling snippet is below (button click starts it up)
<script>
require([
'dojo/dom',
'dojo/_base/array',
'demo/testModule',
'esri/SpatialReference',
'esri/geometry/Point'
], function (
dom,
arrayUtils,
testModule,
SpatialReference,
Point
) {
//Here is the button click listener
$('#whereAmIButton').click(function () {
var spatialRef = new esri.SpatialReference({ 'wkid': 4326 });
//variable I want to set to a returned geometry.
var myGeom;
//This runs but I'm missing the boat on the return of a value
testModule.findUserLocPT(spatialRef);
//var myModule = new testModule(); //not a constructor
});
});
</script>
Here is the custom module. It logs the information to the console for the user's location. But I want to return the value for setting the 'myGeom' variable.
define(['dojo/_base/declare','dojo/_base/lang','dojo/dom',
'esri/geometry/Point','esri/SpatialReference'], function (
declare, lang, dom, Point, SpatialReference) {
return {
findUserLocPT: function (spatialRef) {
var geom;
var location_timeout = setTimeout("geolocFail()", 5000);
navigator.geolocation.getCurrentPosition(function (position) {
clearTimeout(location_timeout);
var lat = position.coords.latitude;
var lon = position.coords.longitude;
setTimeout(function () {
geom = new Point(lon, lat, spatialRef);
//console.log writes out the geom but that isnt what I am after
console.log(geom);
//I want to return this value
return geom;
}, 500);
});
function geolocFail() {
console.log("GeoLocation Failure");
}
}
}//end of the return
});
Any help would be welcome. I can by reference back change textual/html values on the document but am not getting things back as a variable.
Andy
Ok, I don't know if this is the 'best' answer but I have one now.
I added a global variable inside the 'test.html' page
<script>
var theGeom; //This is the variable
require([
'dojo/dom',
here is where I am setting the value of this variable for use in the original dojo 'require' code block. This is coming from the 'testModule.js'
setTimeout(function () {
geom = new Point(lon, lat, spatialRef);
theGeom = geom; //Here is the feedback of the value to the global variable.
return myGeom;
}, 500);
$('#whereAmIButton').click(function () {
var spatialRef = new esri.SpatialReference({'wkid':4326});
testModule.findUserLocPT(spatialRef);
setTimeout(function () {
console.log(theGeom); //here is the value set and ready to use
},2000);
});
I'm not sure if this is the best way. If you have something better please let me know.
Andy

Set object variable from inside method

I'm stuck at this issue where I can't seem to assign a new value to the created object variable. See below:
// Vesselposition class
function vessel(name,ajaxName,dataUrl,pointLimit,polylineColor,iconUrl) {
this.name = name;
this.ajaxName = ajaxName;
this.dataUrl = dataUrl;
this.pointLimit = pointLimit;
this.polylineColor = polylineColor;
this.iconUrl = iconUrl;
// Global variables
this.lat=0;
this.lng=0;
this.latlng;
this.dateTime, this.vesselIcon, this.marker, this.polyline, this.localTemp, this.localWindSpeed, this.localWindDir;
this.countryName, this.countryCode, this.localTime, this.localSunrise, this.localSunset, this.countryFlag;
this.localTemp, this.localWindSpeed, this.localWindDir, this.myOptions, this.ib;
// Function gets position data
this.getData = function() {
$.when(
$.getJSON(this.dataUrl, { vessel: this.ajaxName, limit: this.pointLimit })
).done(function (data){
this.path = [];
// Create vessel icon for marker
this.vesselIcon = new google.maps.MarkerImage(this.iconUrl,
// This marker is 60 pixels wide by 58 pixels tall.
new google.maps.Size(60, 58),
// The origin for this image is 0,0.
new google.maps.Point(0,0),
// The anchor for this image is centered at 30,29 pixels.
new google.maps.Point(30, 29)
);
if (data.markers.length < 1) {
document.getElementById("map_canvas").innerHTML = "<h2>There was a problem obtaining vessel data, wait a couple of minutes and refresh your browser!</h2>";
} else {
for(i=0;i<data.markers.length;i++) {
// Assign lat,lng, id, dateTime and heading
this.lat = data.markers[i].marker.lat;
this.lng = data.markers[i].marker.lng;
What I want to accomplish is to assign this.lat and this.lng the coordinate values inside the for-loop. Later on, those values should be passed on to the getData method.
Please help guys! Been stuck on this for 3 hours searching the web!
Try this:
//keep a reference to this
var self = this;
// Function gets position data
this.getData = function() {
....
//use self here
self.lat=
I found a solution. By using jQuery's proxy function.. I got it to work.
// Function gets position data
this.getData = function() {
$.when(
$.getJSON(this.dataUrl, { vessel: this.ajaxName, limit: this.pointLimit })
).done($.proxy(function (data){
this.path = [];
),this}
Using the same class variables as first provided.. the key is to use $.proxy method in the .done function with the scope "this".

Categories

Resources