JavaScript set value for variable failed - javascript

I'm new to javascript. I'm trying to set value to variable with the following code but failed. Someone please help point out what is wrong with my code.
When I try to print out the value of variable "deviceLatitude", it give me "undefined". But if I print the value from inside the function, it give me the correct value. What have I done wrong?
The reason I need to have global variable for this value is because I need to use it in later stage such as compare distance with different location as needed.
var deviceLatitude;
var deviceLongitude;
function suc (p) {
deviceLatitude = p.coords.latitude;
deviceLongitude = p.coords.longitude;
// alert(deviceLatitude);
}
intel.xdk.geolocation.getCurrentPosition(suc);
alert(deviceLatitude);

suc is being called back asynchronously, so when you issue the alert after the call to intel.xdk...., suc hasn't been called yet.
Note the documentation, my emphasis:
Use this command to get the current location. This command
asynchronously acquires the approximate latitude and longitude of the
device. When data is available, the success function is called. If
there is an error getting position data, the error function is called.
Therefore, if you want to do something with deviceLatitude, you'll have to do it inside the callback.
If you're a promises type of guy, you could do:
function getCurrentPosition() {
return new Promise(function(resolve, reject) {
intel.xdk.geolocation.getCurrentPosition(resolve, reject);
});
}
getCurrentPosition.then(
function(p) {
//do something with p.coords.latitude
},
function() {
//something went wrong
}
);

Try to make anonymous function for success and other for error.
Then create another function which will be called by async when data is available.
function overrideLocalStore(lat, log)
{
alert("lat"+lat+" long"+long);
localStorage.setItem("deviceLatitude", lat);
localStorage.setItem("deviceLongitude", log);
}
intel.xdk.geolocation.getCurrentPosition(
function(p)
{
alert("geolocation success");
if (p.coords.latitude != undefined)
overrideLocalStore(p.coords.latitude, p.coords.longitude);
},
function()
{
alert("geolocation failed");
getLocation();
}
);
// Use whatever you need
alert(localStorage.getItem("deviceLatitude"));
alert(localStorage.getItem("deviceLongitude"));

As pointed out by #torazaburo, it's not possible to get data of asynchronously function out into global variable.
But to achieve what is needed, a workaround can handle that. Since this is HTML5 app, one can use localStorage to save the value and access it anytime later from other screen/function.
A simple example code will be as below:
intel.xdk.geolocation.getCurrentPosition(
function(p) {
if (p.coords.latitude != undefined) {
localStorage.deviceLatitude = p.coords.latitude;
localStorage.deviceLongitude = p.coords.longitude;
}
},
function() {
alert("geolocation failed");
}
);

Related

Odoo javascript change value

I Use odoo 10 and want to change pivot_view.js
I'm really confused with this code. I can't change the value.
Can you explain me about the right code ?
This is my code :
var value = false;
new Model('lhp.master').call('getValues', ['date', 'idx']).then(
function (result) { value = result[0]; }
);
console.log('value =',value);
Thank you for your help.
I think the problem is with how javascript promises work!
The order of the execution of the code is a s follows:
var value = flase;
calling the server method getValue by sending an http request;
console.log('value =',value); // which will print "value =fasle" on the console
after the http request earlier in step 2 is finished and a response is retrieved from the server. The callback function will be called with the result:
function (result) { value = result[0]; }
So, make sure to write the console.log part inside the callback method, like this:
function (result) {
value = result[0];
console.log('value =', value);
}

Async.eachSeries executing in parallel

I'm trying to understand async library from node.js and apply it, but it doesn't work as expected. Called are made in parallels when I was expecting them to be made in series (i.e. one after another)
Here is my code
var users = [{_id:'1',username:'user1'},{_id:'2',username:'user2'}];
async.eachSeries(users,function function1(user,callbackEach){
var username = user.username;
var incomes = [{source:'sourceA',provider:providerA},{source:'sourceB',provider:providerB},{source:'sourceC',provider:providerC}];
async.eachSeries(incomes,function function2(income,callbackSmallEach){
var source = income.source;
income.provider.getEarnings(user._id,username,yesterday,function callbackFromGetEarnings(err,result){
if (err){
// error
} else {
income.earnings = {day : new Number(result)};
income.provider.getMonthEarnings(user._id,username,yesterday,function callbackFromGetMonthEarnings(err,monthTotal){
if (err){
// error
} else {
income.earnings.month = new Number(monthTotal);
callbackSmallEach();
}
});
}
});
},
function sendEmails(err){
if (err) {
// error
} else {
// send email
}
});
console.log("Just before calling callbackEach()");
callbackEach();
});
getEarnings and getMonthEarnings use an external provider, so some time can occur until callback functions callbackFromGetEarnings and callbackFromGetMonthEarnings are called.
My problem is that I dont want both calls to getEarnings to be executed in parallel. I want function getEarnings for user2 to be called only after getEarnings for user1 has returned (and corresponding callbacks have been made).
As you can see I have tried to make the calls for user1 and 2 in a serie, with async.eachSeries but calls are made in parallel. When I execute, the log Just before calling callbackEach() is always executed before the callback function callbackFromGetEarnings is called...
I hope this is clear enough.
The problem is where you are calling your callback. Example:
async.eachSeries(something, function(item, callback) {
async.eachSeries(item.somethingElse, function(subitem, callback2) {
//do something
return callback2();
}, function() {
//when all item.somethingElse is done, call the upper callback
return callback();
})
}, function() {
console.log('done');
})
This way, for each item in something, you will execute in series all the item.somethingElse, before going to the next item.

script doesn't allow geolocation.getCurrentPosition to finish its callback function

I need to package the user's current location into an object and send it off to a PHP script. So what I have currently is the following.
position object
function position(lat, lon) {
this.latitude = lat;
this.longitude = lon;
this.setlat = function(lat) {
this.latitude = lat;
};
this.setlon = function(lon) {
this.longitude = lon;
};
this.print = function() {
alert(this.longitude + ", " + this.latitude);
};
}
control flow
var origin = new position(0, 0);
$(document).ready(function() {
getLocation();
origin.print();
});
functions
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(setLocation, showError, {timeout:60000});
} else {
alert("GeoLocation is not supported on this browser or device.");
return null;
}
}
function setLocation(position) {
alert('callback success!');
origin.setlat(position.coords.latitude);
origin.setlon(position.coords.longitude);
}
function showError(error) {
switch(error.code) {
case error.PERMISSION_DENIED:
console.log("User denied the request for Geolocation.");
break;
case error.POSITION_UNAVAILABLE:
console.log("Location information is unavailable.");
break;
case error.TIMEOUT:
console.log("The request to get user location timed out.");
break;
case error.UNKNOWN_ERROR:
console.log("An unknown error occurred.");
break;
}
}
The problem is that before the setLocation callback is being called, the main control flow continues and ignores the fact that I asked it get something for me. I call getLocation and I get an alert of "0, 0" since that's what origin is originally set to. So for some reason my setLocation callback just isn't getting called until everything else in the program is done.
I've looked around in the documentation, but it's rather straightforward and there isn't a whole lot going on so it's hard to pin down why this is happening.
I know a lot of people have struggled with this and there seems to be a lot of sort of 'look at this topic' but all of these topics point to code that is effectively the same as my own, but formatted a little differently.
It's important to note that I really need this position data encapsulated in a global variable since I'll be comparing my location with several dozen other locations on page-load.
attempted solutions
I've tried restricting my navigator.geolocation.getCurrentPosition() to a while loop that exits based on the completion of the callback function, but this always results in an unending loop.
-I've tried playing with the maximumAge and timeout values in the PositionOptions in order to allow the function some time to finish, but again this just results in setLocation finishing after all other scheduled function calls are done.
-I've tried using two seperate $(document).ready(function(){}); in order to segment the getLocation() and origin.print() functions.
-I've tried using watchPosition instead of getCurrentPosition.
Ultimately I really just need some clarification on why the callback function in getCurrentPosition isn't finishing until everything else does.
While it doesn't really seem all that different from performing logic in your callback function for getCurrentPostion there are some technologies in Javascript which allow you to deal with asynchronicity in this way, and thus considerably clean up your code. What I'll demonstrate below is using jQuery's $.Deferred object to grab your current location and package it into a variable which can be used by other functions.
function getLocation() {
var deferred = $.Deferred();
setTimeout(function() {
navigator.geolocation.getCurrentPosition(function(pos) {
origin = new position(pos.coords.latitude, pos.coords.longitude);
deferred.resolve();
});
}, 2000);
// 2.00 seconds
return deferred.promise();
}
It's important to note that we're instantiating the origin and resolvin the deferred object with deferred.resolve() in the same scope.
Now what we'll have to do is call getLocation() but with some added syntax to specify that the functions dealing with objects resolved inside getLocation() must wait until it's finished to access them.
getLocation().done( function() {
origin.print();
//do other stuff with origin
});
This will successfully print your coordinates, and you're free to do anything else with the data gotten by getCurrentPosition, like using Google Maps.
You can replace this:
var origin = new position(0, 0);
$(document).ready(function() {
getLocation();
origin.print();
});
with this
var origin = new position(0, 0);
$(document).ready(function() {
getLocation();
});
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(setLocation, showError, {timeout:60000});
} else {
alert("GeoLocation is not supported on this browser or device.");
return null;
}
}
// this is the callback
function setLocation(position) {
alert('callback success!');
origin.setlat(position.coords.latitude);
origin.setlon(position.coords.longitude);
// this is a new function that makes stuff
processLocation();
}
// do your stuff here
function processLocation(){
origin.print();
// do your stuff here like comparing to other locations or sending data
if (origin.latitude == something) blah...
}
Basically do your logic inside a function and call it inside the setLocation callback

How could I optimize this code with too many nest functions?

I'm writing a Chrome extension with the socket api(though this doc is out of date, the latest version of the api is here), and I found that the code is really hard to organize:
All the methods are under the namespace chrome.experimental.socket, I would just use socket below for simplicity.
socket.create("tcp", {}, function(socketInfo){
var socketId = socketInfo.socketId;
socket.connect(socketId, IP, PORT, function(result){
if(!result) throw "Connect Error";
socket.write(socketId, data, function(writeInfo){
if(writeInfo.bytesWritten < 0) throw "Send Data Error";
socket.read(socketId, function(readInfo){
if(readInfo.resultCode < 0) throw "Read Error";
var data = readInfo.data; // play with the data
// then send the next request
socket.write(socketId, data, function(writeInfo){
socket.read(socketId, function(readInfo){
// ............
});
});
});
})
});
})
because both socket.write and socket.read are asynchronous, I have to nest the callbacks to make sure that the next request is send after the previous request got the correct response.
it's really hard to manage these nested functions, how could I improve it?
UPDATE
I'd like to have a method send which I can use as:
send(socketId, data, function(response){
// play with response
});
// block here until the previous send get the response
send(socketId, data, function(response){
// play with response
});
How about (something like) this?
var MySocket = {
obj: null,
data: null,
start: function() { ... some code initializing obj data, ending with this.create() call },
create: function() { ... some code initializing obj data, ending with this.connect() call },
connect: function() { ... some connection code, ending with this.write() call },
write: function() { ... some writing code that updates this.data, ending with this.read() call },
read: function() { ... you probably get the idea at this point )) ... },
};
This object could be used with MySocket.start() or something. The idea is to encapsulate all data (and nested calls) within the single (yet more-o-less globally usable) object.
Or even more, one can create two objects: one purely for writing purposes, and another for purely reading, each operating with its own data, then wrap them (and their inter-calls, so to speak) into a single SocketManager object.
Consider using an asynchronous continuation passing style, where functions end with a SetInterval call with the function they were passed. Then we construct a function that entwines two functions to call each other using this mechanism. The guts of it would be like this:
var handle;
// pairs two functions
function pair(firstfunc, secondfunc, startarg) {
var callbackToFirst = function(valuetofill) {
handle = setInterval(firstfunc(valuetofill,callbackToSecond));
};
var callbackToSecond = function(valuetofill) {
handle = setInterval(secondfunc(valuetofill,callbackToFirst));
};
callbackToFirst(startarg);
}
What we are doing here is constructing a pair of mutually-calling callbacks which take a single argument, which each contain references to the two inter-calling functions. We then kick off the process by calling the first callback.
Construct the pair for an example pair of read and write functions (assuming you've set the socketId in the enclosing object definition):
// starts read/write pair, sets internal variable 'handle' to
// interval handle for control
function startReadWrite(initialarg, myDataFunc) {
var readcall = function(value, func) {
readSocket(getData(myDataFunc(func)));
};
var writecall = function(value, func) {
writeSocket(checkBytesWritten(func));
};
handle = pair(readcall, writecall, initialarg);
}
The rest of the object is like this:
function myIO() {
var socketInfo, socketId, handle;
function create(func) {
socket.create('tcp',{},function(thisSocketInfo) {
socketInfo = thisSocketInfo;
}
setInterval(func(this),0);
}
function connect(IP, PORT, func) {
socket.connect(p_socketId, IP, PORT, function() {
if(!result) throw "Connect Error";
setInterval(func(result),0);
});
}
function readSocket(func) {
socket.read(p_socketId, function(readInfo){
setInterval(func(readInfo),0);
});
}
function writeSocket(data, func) {
socket.write(p_socketId, data, function(writeInfo){
setInterval(func(writeInfo),0)
});
}
function checkBytesWritten(writeInfo, func) {
if(writeInfo.bytesWritten < 0) throw "Send Data Error";
setInterval(func(writeInfo),0);
}
function getData(readInfo, func) {
if(readInfo.resultCode < 0) throw "Read Error";
var data = readInfo.data;
setInterval(func(data),0);
}
//** pair and startReadWrite go here **//
}
Finally the call to set the whole thing going:
var myIOobj = new myIO();
myIOobj.create(startReadWrite(myDataFunc));
Notes:
This is meant to demonstrate a style, not be ready code! Don't just copy and paste it.
No, I haven't tested this; I do javascript but not Chrome API stuff yet. I'm focussing on the callback mechanisms etc.
Be careful with the different classes of callback; single argument callbacks (like the read and write callbacks) which take a single value (as presumably defined by the API), and 2 argument callbacks (like most of the methods) which take an argument and a function to call at the end.
The getData method takes a callback and passes data to it; this callback (myDataFunc) is the function that actually gets to use the data. It needs to take a callback as a second argument and call it synchronously or asynchronously.
TLDR: Consider using asynchronous calls to avoid the nesting. I've given a vague example of a mechanism to have two functions call each other continuously using this style as seems to be needed.
Although I call it asynchonous, the setInterval calls will execute serially, but the key is that the stack is cleared after the parent call is done, rather than adding endless layers with nesting.

Jquery $.post() variable scope

I'm not massively experienced with JavaScript and I'm having trouble with variable scope and jquery. I have the following structure:
function pass_variables()
{
username = "efcjoe"
response = post_variables(username)
alert(response)
}
function post_variables(username)
{
$.post(
'/path/to/url/',
{
'username': username,
},
function(data)
{
valid = (data != 0) ? true : false
// OPTION 1: If I put return here...
return valid; // ... the alert box in pass_variables says "undefined"
},
"text"
);
// OPTION 2: If I put return here...
return valid; // ... The alert box does not pop up, and Safari debug gives
// me the error: "Can't find variable: valid"
}
Am I missing something there? I think valid should be a global variable, and therefore option 2 should work fine. I'm really not sure about option 1.
Can anyone give me any advice on the best way to get this working?
Thanks a lot.
Ajax calls are asynchronous which means they get called but do wait around for execution to complete. Basically your alert is firing before the ajax request has completed and run the callback function to change your variable.
The best thing you can do is actually pass a function to run when the ajax request has completed. This also negates the need for global variables which are frowned upon since other plugins, script can alter their state and leave your script open to errors, flaws etc
E.g
function foobar(){
//call function to do post request and also pass a function to run
//when post has returned
runPostRequest( callbackFn );
}
function runPostRequest(callback){
$.post( '/foo', callback );
}
function callbackFn( data ){
console.log('post request complete');
}
In your option 1 you are returning from the callback function, and its return value is never used because this function is only called when the Ajax request ends.
In the option 2, you are returning from your main function, but that return happens before the callback function assign any value to your valid variable.
I would refactor your code in this way, without using global variables:
function post_variables(username){
$.post('/path/to/url/',{
'username': username,
},
function(data){
var valid = data != 0;
// OPTION 3: Work in the callback function
alert(username);
alert(valid);
// OPTION 4: Pass the values and work on another function
otherFunction(username, valid);
},"text");
}
function otherFunction(username, isValid){
//...
}
Yeah, your problem is that you're not grasping some order of operations issues here. The function you're passing to $.post is a callback; it runs later, considerably after post_variables() finishes. post_variables() itself does not wait for the $.post to finish, so valid doesn't exist when you're trying to use it.
Remember that AJAX is asynchronous. The return valid; gets executed immediately after the $.post() is set up, but before the post has completed (and therefore, before valid is defined). What you probably want to do is this:
function post_variables(username)
{
var username = "efcjoe";
$.post(
'/path/to/url/',
{
'username': username,
},
function(data)
{
var valid = (data != 0) ? true : false
alert(valid);
},
"text"
);
}
And note that this no longer needs global variables, but function-scope variables that are declared using var.
You could solve the problem quite easily by assigning it a function instead of an inline one, and the event function does the alert:
function pass_variables()
{
username = "efcjoe"
response = post_variables(username);
}
function post_variables(username)
{
$.post(
'/path/to/url/',
{
'username': username,
},
receivedData,
"text"
);
}
function receivedData(data)
{
valid = (data != 0) ? true : false;
alert(valid)
}

Categories