I have seen, google places api docs, suggesting use of global variables outside of the functions, like:
var placeSearch, pauto, geocoder;
I want to use data returned from $.get, outside of the function.
Could I also use a global variable that will be fed by data inside a callback function?
var glo_var;
function callback(data){
glo_var = data;
}
function codeAddress(address) {
geocoder.geocode({ 'address': address},
function(response, status) {
if (status == 'OK')
{
var senddata = $.get('/myurl',{params}, function (data){ callback(data) });
} else {
}
});
}
Any other way, that I could make use of returned datafrom $.get. I do not understand closures.
EDIT - Why is this a duplicate, I am asking where to store the returned data, I already know how to get it? It's the use of globals that i am not sure of, but since google api uses it, i asked about it here.
so the reason for to avoid using global variables as much as possible as stated in the previous answers. It is about easily overriding problem and troubleshooting when some global values are being overriden. From my own experience, I usually create an utility to handle sharing values. The idea is as following
//global.js
(function(){
const context = {};
function setGlobalValue(key, value) {
context[key] = value;
}
function getGlobalValue(key) {
return context[key];
}
window.setGlobalValue = setGlobalValue;
window.getGlobalValue = getGlobalValue;
}());
// app.js
function codeAddress(address) {
geocoder.geocode({ 'address': address},
function(response, status) {
if (status == 'OK')
{
var senddata = $.get('/myurl',{params}, function (data){ setGlobalValue('codeAddress', data) });
} else {
}
});
}
// get value here
console.log(getGlobalValue('codeAddress'));
by this way we can track all the global values by searching for setGlobalValue since this is the only way to set "global" value context.
You can just wrap everything inside self invoked function (it's closures but it's simple)
(function(){...})() means function will call itself, that's all.
Best practice is when you wrap every .js file inside this self invoked function so it's not global.
Your code:
(function(){
var glo_var;
function callback(data){
glo_var = data;
}
function codeAddress(address) {
geocoder.geocode({ 'address': address},
function(response, status) {
if (status == 'OK')
{
var senddata = $.get('/myurl',{params}, function (data){ callback(data) });
} else {
}
});
}
})();
Avoid global variables or minimize the usage of global variables in JavaScript. This is because global variables are easily overwritten by other scripts. Global variables are not bad and not even a security concern, but it shouldn’t overwrite the values of another variable.
On the usage of more global variables in our code, it may lead to a maintenance issue. Let’s say we added a variable with the same name. In that case, get ready for some serious bugs.
To avoid the usage of global variables, use the local variables and wrap your code in closures. You can also avoid this by wrapping the variables with json:
var wrapperDemo= {
x:5,
y:function(myObj){
}
};
Above, if you want to call x, then call it using:
wrapperDemo.x
Which would return 5 for you...
Related
I'm basically trying to call a function which is outside of my AJAX inside the AJAX success response.
To explain this better, this is what I have.
These are two functions:
function watchCurrentPosition() {
var positionTimer = navigator.geolocation.watchPosition(function(position) {
setMarkerPosition(userLocation, position);
map.panTo(new google.maps.LatLng(position.coords.latitude, position.coords.longitude));
});
}
function clearmyWatch() {
navigator.geolocation.clearWatch(positionTimer);
}
One of them keeps watching the users location and the other one 'should' stop it.
And this is how I'm calling the clearmyWatch(); function inside the AJAX:
$.ajax({
type:"post",
url:"TEST.PHP",
datatype:"html",
success:function(data)
{
clearmyWatch();
}
});
However, this doesn't work and the watchCurrentPosition(); constantly running and I also get an error in my console.
The error that I am getting is this:
ReferenceError: positionTimer is not defined
Could someone please advise on this issue?
Thanks in advance.
You need to define positionTimer at global level outside of function watchCurrentPosition() like:
var positionTimer = null;
function watchCurrentPosition() {
positionTimer = navigator.geolocation.watchPosition(function(position) {
setMarkerPosition(userLocation, position);
map.panTo(new google.maps.LatLng(position.coords.latitude, position.coords.longitude));
});
}
function clearmyWatch() {
if(positionTimer)
navigator.geolocation.clearWatch(positionTimer);
}
positionTimer is local to watchCurrentPosition
The better way to solve it without global variables is:
function watchCurrentPosition() {
var positionTimer = navigator.geolocation.watchPosition(function(position) {
setMarkerPosition(userLocation, position);
map.panTo(new google.maps.LatLng(position.coords.latitude, position.coords.longitude));
});
clearmyWatch=()=>{
navigator.geolocation.clearWatch(positionTimer);
}
}
function clearmyWatch() {}
Explanation: clearmyWatch is defined in a way that it does nothing.However calling watchCurrentPosition sets clearmyWatch as an inner function of watchCurrentPosition that can get to positionTimer. Actually by setting clearmyWatch to an inner function of watchCurrentPosition we create a closure (read about it of you don't know what it is, it's important).
I hope you can help. Ive made a function that receives a lnglat point object and returns just the town. I can get it to print the correct town in the console.log but it doesnt return the data back from the function.
I know its going to be a basic error but can someone have a look at the code and let me know please.
Thanks in advance.
function getTownFromPoint(point){
var geocoder ;
var geocoder = new google.maps.Geocoder();
var townset = false;
mylocation = "";
geocoder.geocode({latLng: point}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
var components=results[0].address_components;
for (var component=0;component<(components.length);component++){
if(components[component].types[0]=="country" & !townset){
mylocation = components[component].long_name;
}
if(components[component].types[0]=="postal_code" & !townset){
mylocation = components[component].long_name;
}
if(components[component].types[0]=="locality"){
mylocation = components[component].long_name;
townset = true;
console.log(mylocation);
}
}
}
}
});
return(mylocation);
}
Geocoder is asynchronous - You are returning the value before you value is set.
It has been answered here:
Waiting for google maps geocoder?
That's because geocode is an ajax call and they are asynchronous. You need to provide a callback function or use a a promise to get the data. Since you're not using jQuery by the looks of your question a callback might be easier:
Here's a simplified version of your code with an example of how the callback function can be used:
// we pass in the callback as a function parameter
function getTownFromPoint(point, callback) {
geocoder.geocode({
latLng: point
}, function (results, status) {
var myLocation = results.myLocation;
// then we call the callback with the myLocation variable
callback(mylocation);
}
);
}
// call the function with the point variable and the function
// we will use for our callback
getTownFromPoint(1.223, function (myLocation) {
console.log(myLocation)
});
The problem you're facing is that you're treating the geocoder.geocode function as immediately completing before you do the return result. What's really happening is that the geocoder.geocode is triggered, then you get an immediate return of result. Because the asynchronous result has most likely not returned, your result is empty. Think of the geocoding result as a push, not a pull. The storeResult function, not shown, is whatever code you need to do to save the information. Because you're combining a result with an error string, you have to handle that in your storeResult function. As an alternative, you can have a status in the result that indicates succcess or failure.
store the result:
storeResult(result);
use this function inside your function. this will solve your problem
This question already has an answer here:
Saving geocoder results to an array - Closure Trouble
(1 answer)
Closed 9 years ago.
I have a function
function getCustomAddress() {
alert(results[i].formatted_address)
}
alert(results[i].formatted_address) is defined in another function. It clearly means that it is undefined in getCustomAddress, so how do I resolve this issue and alert the values. I have set up a fiddle as well.
http://jsfiddle.net/KEdrq/5/
You could just pass it as a function parameter
function getCustomAddress(result) {
alert(result.formatted_address)
}
so when you call the function you need to supply one parameter:
getCustomAddress(results[i]); for example
You could create a private scope with a function and define all your global variables there:
(function(){
var results = [];
function getCustomerAdress(){
//... call result etс
}
function set result(){
//... set result etc
}
// some code for initialization, setting onload handlers etc
})();
I checked out the jsFiddle, the results are fetched as an ajax request.
You need to store the results in a variable with a global scope and then set a timeout to fetch the result. You can also execute your function before the end of geocoder request and pass it the results variable.
geocoder.geocode(geocoderRequest, function (results, status) {
// execute your function here. getCustomAddress(result)
}
Check the changes I have made.
http://jsfiddle.net/KEdrq/7/
Summary of code changes.
var _results;
function initialize() {
.
.
.
google.maps.event.addListener(marker, 'dragend', function (e) {
getAddress(e.latLng);
setTimeout('getCustomAddress(0);', 500);
})
function getAddress(latLng) {
if (!geocoder) {
geocoder = new google.maps.Geocoder();
}
var geocoderRequest = {
latLng: latLng
}
geocoder.geocode(geocoderRequest, function (results, status) {
_results = results;
.
.
.
function getCustomAddress(i) {
alert(_results[i].formatted_address)
}
You might want to create a for loop to alert all the results instead of passing the result id in the getCustomAddress function.
I'm a c++ programmer so the following undefined variable error in java script is strange for me. I've defined a global variable ,directionResult and the following code initializes its value :
function calcRoute() {
var iMap = {
departure:"tiran,esfahan",
destination:"esfahan"
}
var request = {
origin : iMap.departure,
destination : iMap.destination,
travelMode : google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
document.getElementById("log").innerHTML = result.routes[0];
directionResult = result;
}
});
}
in the last if directionResult will be equal to result which is a parameter to a call-back function. But in another function :
function showSteps() {
var myRoute = directionResult.routes[0].legs[0];
var point = myRoute.steps[index].start_point;
var inst = myRoute.steps[index++].instructions;
obj.setPosition(point);
document.getElementById('inst').innerHTML = inst;
map.panTo(point);
if (index >= myRoute.steps.length)
clearInterval(timer);
}
when I want to use directionResult at the first line,I encounter this error:
TypeError: directionResult is undefined
How can I solve this strange behavior?thanks.
One possible reason directionResult is undefined may be because you are trying to reference it before it has been set. Although your showSteps() function appears after the calcRoute() function, directionResult is not set until the directionsService.route() callback is fired, which happens (presumably) after an AJAX request.
Try calling showSteps() from within the directionsService.route() callback function instead.
I would like to update some data with JSON when the user clicks on an object. What I came up with is the following double closure.
var buildGetJSON = function(m,t,p,u) {
return function () {
var buildUpdateParticipants = function(m,t,p) {
return function(data) { updateParticipants(m,t,data,p); };
};
$.getJSON(u, buildUpdateParticipants(m,t,p));
};
};
marker.on("click", buildGetJSON(marker, title, popmsg, url));
It works, but made me wonder if there is a more concise way to put this than writing a closure variable for the two function calls. Any hints?
Yes, the second closure is redundant.
function buildGetJSON(m,t,p,u) {
return function() {
$.getJSON(u, function(data) {
updateParticipants(m,t,data,p);
});
};
}
marker.on("click", buildGetJSON(marker,title,popmsg,url));
If you're only using buildGetJSON once, you can further simplify it by making buildGetJSON anonymous.
marker.on("click", function(m,t,p,u) {return function() {
$.getJSON(u, function(data) {
updateParticipants(m,t,data,p);
});
};}(marker,title,popmsg,url));
Here's another way to do it entirely with anonymous functions. It doesn't collapse into as few lines, but I think it looks a little clearer.
!function(m,t,p,u) {
marker.on("click", function() {
$.getJSON(u, function(data) {
updateParticipants(m,t,data,p);
});
});
}(marker,title,popmsg,url);
Why not simply do this?
marker.on("click", function () {
$.getJSON(url, function (data) {
updateParticipants(marker, title, data, popmsg);
});
});
Looks much more synoptical - at least to me :-)
But be aware: if the variables marker, title etc. can change, and you don't want that, then you need an additional closure. E.g. if you call this for example in loop, and the variable marker (or other variables) changes over the loop! Then you need to enclose your code in another closure within the loop:
for (marker in markers) {
(function (marker) {
// above code
})(marker);
}
Closures are very nice and very strong feature of JavaScript, once you know how to use them. Look at the "The JavaScript Programming Language" videos from Douglas Crockford, they explain it in a great way.