Calling a function inside an AJAX success response? - javascript

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).

Related

Should global variables in javascript be always avoided?

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...

using getJSON in a class (scoping issue)

//this is a class
function SpriteSheetClass()
{
this.sprite="local";
$.getJSON(url, this.onLoaded);
}
SpriteSheetClass.prototype.onLoaded= function(json)
{
console.log(this.sprite); //returns undefined!
//I am out of SpriteSheetClass scope! how do I store the json???
}
var a=new SpriteSheetClass()
When the getJSON callback is executed, the scope is not in the class.
There is no way to bind the returned json with my class instance (a)
Keep in mind I want to keep the calls async, and I need to create many instances of SpriteSheetClass
This is not a timing question, it is a scope question.
thanks
When the callback function is called, this will not be the object, but the $.getJSON function.
You can bind the value of this to the callback, so it will be the object instead
$.getJSON(url, this.onLoaded.bind(this));
FIDDLE
With modern day browsers you can use function.bind(thisArg) to keep the proper scope.
function SpriteSheetClass() {
this.sprite="local";
$.getJSON(url, this.onLoaded.bind(this));
}
A local wrapper function will do the job:
function SpriteSheetClass()
{
this.sprite="local";
var that = this;
var callback = function(data) {
that.onLoaded(data);
};
$.getJSON(url, callback);
}

js execute function after object is defined

I need for a function to be executable only after an object is defined, I'm currently working in a fascade pattern and one method is dependent on another method. in this case 'addNewLayer' fails because 'setFullMap' hasn't finished executing. is there a solution? I'm using jquery and vanilla js so most any solution would be helpful at this point:
var jen = (function(){
function setFullMap(mapID){
jen.map = new Map(mapID);
}
function setLayer(opt){
//execute code here after jen.map is defined
}
return{
samp: function(id, opt){
setFullMap(id);
addNewLayer(opt);
}
};
})();
Thanks
solution:
var jen = (function(){
function setFullMap(mapID, callback) {
jen.map = new Map(mapID);
if(jen.map){
callback();
}
}
return {
samp: function(id, opt){
setFullMap(id, function(){
addNewLayer(opt);
}.bind(this));
}
};
})();
You will have to pass a callback function to setFullMap, and execute it once the function has completed (at the very end, before the closing }).
var jen = (function(){
function setFullMap(mapID, callback){
jen.map = new Map(mapID);
callback();
}
function setLayer(opt){
//execute code here after jen.map is defined
}
return{
samp: function(id, opt){
setFullMap(id, function() {
addNewLayer(opt);
}.bind(this));
}
};
})();
Do not forget using .bind(this) - it is very important in order to keep the original this in your callback function.
Edit:
Actually that would not work work if the Map constructor is a-synchronous. If you do not have access to the constructor and/or you cannot pass it a callback, then presumably the only (and sad) option would be to use a setTimeout or (easier) setInterval, continuously checking at defined intervals if the operation has been completed, and then fire the callback.
You could use a callback parameter:
function setFullmap(mapId,callback) {
jen.map = new Map(mapId);
callback();
}
....
samp: function(id, opt){
setFullMap(id,function() {
addNewLayer(opt);
});
}
When u dont have a way to manipulate the Map Object then u need to use a loop:
var loop=self.setInterval(function(){
if(jen.map) {
//execute code here after jen.map is defined
console.log(typeof jen.map);
window.clearInterval(loop);
}
},50);
Check jsfiddle:
http://jsfiddle.net/9yv5t/1/
I have checked the docs and it seems that there are various events you could listen to.
For example:
var m = new Map(...);
m.on('load', function () {
//execute code when the first layer is ready
});
var l = new Layer(...);
l.on('load', function () {
//execute code when the layer has been initialized
});
It's also carefully stated for the Layer.load event:
fires after layer properties for the layer are successfully populated.
This event must be successful before the layer can be added to the
map.

How to resolve a Javascript Scope issue. Is closure the answer? [duplicate]

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.

Javascript asynchronous Function Call : Retrieve calling function paramters in callback function

How can I get the user state in Javascript callback function ? Like I have a Javascript funciton making an asynchronous call as follows. Now In callback function I need to access userstate. How can I do this? In Silverlight we have userstate kind of thing. Do we have same kind of mechanism in Javascript as well. Please assist.
Note: I dont want to make use of Global variable as Func1() will be executed in a For Loop.
function Func1() {
var userState = "someValue";
geocoder.asyncCall(parameters , CallBack);
}
function CallBack(result) {
// Use result
// How to access userState in this function
}
Try this code:
function Func1() {
var userState = "someValue";
geocoder.asyncCall(parameters ,function(){
CallBack(userState);
});
}
function CallBack(result) {
// Use result
// How to access userState in this function
}
update
function PlotAddressOnMap(address) {
var address = address;
var userState="userState";
geocoder.geocode({ 'address': address }, CityDetailsReceived(userState));
}
function CityDetailsReceived(userState) {
return function(results, status){
//your code
}
}
function Func1() {
var userState = "someValue";
geocoder.asyncCall(parameters , CallBack(userState));
}
function CallBack(userState) {
return function(result){
// userState is accessible
}
}

Categories