I am using Lawnchair to save data in js and retrieve it back for my mobile app.
I have this in my js file.
$(document).ready(function() {
//Lawchair set up
db = Lawnchair({name: 'db'},function(e){
console.log('storage open');
});
//store the 'username' key in storage
db.save({key:"username", value: "john"});
var name = ""
db.get("username", function(obj){
name = obj.value;
})
alert(name);
});
The problem is I always get "" in the name. I can never set any variable inside the callback function of "get" from Lawnchair object. Am I missing something?
Any help would be appreciated.
Thanks.
The database operation is asynchronous. Put your alert inside the callback to the ".get()" function.
As a general rule, any time you see a JavaScript API like this:
something(param, param, ... , function(result, result, ...) {
// ...
});
it's a good bet that the function may be an asynchronous mechanism, and that the callback function you supply will only be called later when an event actually transpires. In those cases you have to structure your own code such that activities you need to perform after the operation completes are done in code inside the callback.
(It's not always the case; some functional programming APIs for example take functions as arguments.)
Related
I am trying to export a function that will let you put in a parameter (trading pair) and it will return the data for that trading pair. This is the code that creates a function that:
Accepts a parameter (trading pair).
Returns the data for that trading pair in the form of a Promise.
Then calls another function which processes that data.
// This function is exported and let's you feed in pairs you want data for - feeling proud.
function pullData(coinPair) {
kc.getTicker({
pair: coinPair
}).then(returnData).catch(console.error)
}
// This function is the callback, which I believe means this function is called and fed the results of the Promise returned from 'kc.getTicker'.
// At first it just logs the data, but now I'll need to find a way to return the data as a usable array. Maybe use the 'return()' function?
function returnData(pairData) {
// Nae Nae
//return pairData;
console.log(pairData);
}
// Finally we export our hard work
exports.pullData = pullData;
I now want to simply have the exported function return the data (and for this data to be usable by a callback function.
// Including important sub modules & config files
const tradeData = require('./example');
var config = require('./config');
// Log the config pairs (Method 1):
function logArrayElements(element, array) {
console.log(element);
}
config.pairs.forEach(logArrayElements);
// Was going to cycle through config pairs. However, I will instead have a base strategy that will be replicated for each pair and run side by side.
//console.log(tradeData.pullData('ETH-USDT'));
tradeData.pullData('ETH-USDT', calculations);
function calculations() {
console.log(pairData);
}
The relevant lines here are the including of the file ('./example') and the pitiful attempt at using the function with a callback down lower.
My goal is to be able to pass something like this:
tradeData.pullData('ETH-USDT', calculations);
function calculations() {
// Calculations and logic here
}
That may involve having '.then' simply return the data. I believe this would allow for a 'calculations' function to use the data after the asynchronous function finishes...
Any answers are greatly appreciated as I haven't been able to find guidance as to what I should do here.
I'm not sure what it is you like pullData to return. you would like it to return only the data? So something like this:
function pullData(coinPair) {
return kc.getTicker({
pair: coinPair
})
.catch(console.error) //.then(returnData)
}
And then you'd like it to receive a calculations function that is performed on the data like this:
function pullData(coinPair,calculations) {
return kc.getTicker({
pair: coinPair
}).then(calculations).catch(console.error)
}
Now the caller can do:
pullData(pair,calculations);
But the caller may ass well do:
pullData(par).then(calculations)
I'm not sure what the benefit here is.
My question may have confused others, as I was genuinely lost as to the proper structure to follow.
Upon review the following day, what I was trying to do was:
Create a function that would request data from an API.
Export this function and allow it to be called in other files.
Allow those other files to pass in their own callbacks in order to perform their desired calculations and use the data appropriately.
In my original question, I did not define a callback as a parameter for the data collecting function. As a result, the function would only ever expect one parameter, namely the 'pair'. I believe it would then call '.then()' once the asynchronous process was finished. However, the function it calls would have to be within the original file.
To remedy this I had to add a function, in this case, named 'calculations', as a parameter in the function and then have '.then()' call that function. This told '.then()' to look for the function that would be passed as the second parameter and then call it once the data had been received from the API.
This now means I can export the function to multiple other files and if I want other functions to use the data I just have to pass those functions in with the call.
When trying this simple code:
function create_folder(name, parent_ID) {
var BM_folder = "";
chrome.bookmarks.create({title : name, parent_id : parent_ID }, function (new_folder) {
BM_folder = new_folder;
});
console.log("create folder in id : " + BM_folder.id);
return BM_folder.id;
}
I get undefined as output, but when I debug it works fine and I get the real bookmark ID. I have similar problems in more functions, I guess it's the same problem.
EDIT #1: fixed the vars, my real function has full strings, I simply can't post that way.
EDIT #2: thanks Marco Bonelli, is there a way to turn this into sync, so that I'll be able to use normal oop?
There are several problems in your code:
First of all, that function cannot work... you're using a hypen (-), and variable/function names cannot contain hypens in JavaScript, so change it in something else, maybe create_folder or createFolder. That's the same for your variable BM-folder, and parent-ID. Call them BMFolder and parentID.
Secondly, you are creating the object to pass to chrome.bookmarks.create() in the wrong way: parent-ID is both wrong and undefined. You should do: chrome.bookmarks.create({title: name, parentID: parentid}).
Inside your function, you're calling the chrome.bookmarks.create() method, which is asynchronous: this means that the code is processed separately from the body of your function, and when the method has finished working, it will call the callback function, which you provide as second argument. Basically when calling chrome.bookmarks.create() you have to wait until it's finished to continue, because if you try to access the BMfolder.id variable before the callback gets called it will obviously be undefined.
Now, to summarize what I said above, I'll show the right code for to achieve you're trying to:
function createFolder(name, parentid) {
chrome.bookmarks.create({title: name, parentID: parentid }, function (newFolder) {
console.log("Created the folder with ID: " + newFolder.id);
goOn(newFolder);
});
}
function goOn(BMFolder) {
console.log('Here is the folder: ', BMFolder);
// do something...
}
You cannot use return BMFolder.id, because your function is asynchronous, so the only thing you can do to know that the bookmark folder has been created is to call another function to continue. For example, you can name it goOn().
EDIT:
Is there a way to turn this into sync, so that I'll be able to use normal oop?
Unfortunately you cannot turn an asynchronous function into a synchronous one. Chrome extensions' methods are only asynchronous, therefore you have to work on that. By the way, working asynchronously is much more efficient than working synchronously, and you should get used to this programming style, because (as said before) Chrome extensions only work asynchronously, and so do many other JS frameworks and APIs.
I want to save the value of data and status in a variable and use it after the closing brackets of jquery GET/POST function.But alert comes only when it is inside .get braces.
$(document).ready(function(){
$.get("demo_test.asp",function(data,status){
v = data;
});
alert("Data:"+v);
});
As Jasper said, your alert is being triggered before the request is complete (async!). So, you have two options:
Do your logic inside the callback:
$.get("demo_test.asp",function(data,status){
v = data;
alert("Data:"+v);
//Process stuff here
});
Or pass the received data onto another function and work with it there
$.get("demo_test.asp",function(data,status){
v = data;
doStuff(v);
});
function doStuff(param) {
console.log(param);
}
You're absolutely correct; the code is working as it should... here's why:
The page loads and starts running code, it then hits the .get command and then keeps running, obviously making it to the 'alert' you have next. Since the .get function is still working on fetching the data before your page makes it to the 'alert' part... there's nothing to prompt.
You might want to string things together after the .get, using deferred objects. Look into: http://api.jquery.com/deferred.always/
This is a way of tacking on another function inside of the one fetching your data, so they depend on each other.
Simple answer, yes, you can store the data in a global variable and access it elsewhere. However, you must wait until it is ready.
The better way to do it is to instead store the jqXHR globally and simply add a done callback to it when you need to access the data.
var reqDemoTest = $.get(...);
//... some time later...
reqDemoTest.done(function(data){
console.log(data);
});
I am taking jQuery.Atmosphere.js as an example, in this it has public function such as onMessage, onError etc. And when implementing this api i have done the following
var socket = $.atmosphere;
var request = new $.atmosphere.AtmosphereRequest();
request.onMessage = function(response) {
// do what i want to do
}
Here the onMessage will be trigger whenever the server pushes data to browser. I don't understand how request.onMessage(response) get notified which is outside the atmosphere api? I have looked in to the jQuery.Atmosphere.js and couldn't connect the dots how this works. I am not talking about websocket or server push or anything about atmosphere framework. I just want understand how javascript function callbacks work. Can anyone point me an example how function callbacks work or send me a link so i can dig in?
Your syntax is incorrect, it should be:
request.onMessage = function(response) {
// do what I want to do
};
As you can see, the onMessage property must be set to a function. When the Message event occurs on this object, the function will be called. The jQuery.Atmosphere.js code contains:
f.onMessage(response);
where f is its internal variable representing the AtmosphereRequest object. This function is called from invokeFunction():
function _invokeFunction(response) {
_f(response, _request);
// Global
_f(response, jQuery.atmosphere);
}
_request is a local variable in the AtmosphereRequest constructor, which contains all the state of this request object. This is part of Javascript object oriented programming; all uses of this AtmosphereRequest object have access to these internal state variables.
Can someone tell me why this alert is empty?
var pending_dates = [];
$.getJSON('/ajax/event-json-output.php', function(data) {
$.each(data, function(key, val) {
pending_dates.push({'event_date' : val.event_date});
});
});
alert(pending_dates);
I can't get my head around this. Am I not declaring pending_dates as a global variable, accessible within the each loop? How would one solve this?
Please note that the JSON output is working well. If I would declare pending dates within the getJSON function (and alert within that function), it works, but I need to store the data in an array outside of that getJSON function.
Thanks for your contributions.
EDIT
Thanks to your comments this code is working:
pending_dates = [];
$.getJSON('/ajax/event-json-output.php', function(data) {
$.each(data, function(key, val) {
pending_dates.push({'event_date' : val.event_date});
});
}).success(function() { alert(pending_dates); })
Thanks a lot for your contributions!
I think the problem is $.getJSON is an asynchronous call - it returns immediately and then alert(pending_dates) is invoked.
However, when that happens, the response from the asynchronous call may not have been received, and hence pending_dates may not have been populated.
That is probably why it is empty at the time alert(pending_dates) is called.
Your alert is executing before the JSON call has finished. Remember this JSON it fetched and processed asynchronously, but your alert comes right after it's started. If you want an alert, then you need to put it at the completion of the getJSON call.
$.getJSON is working asynchronously meaning that whatever you have specified in the callback will be executed eventually but there is no guarantee that will happen by the time you reach alert('pending_dates').
You can verify this by moving alert('pending_dates') right after
pending_dates.push() (this would result in one alert being displayed for each item it is retrieving).
You can write a function to start working with the data you're retrieving as soon as it is available:
var pending_dates = [];
$.getJSON('/ajax/event-json-output.php', function(data) {
$.each(data, function(key, val) {
pending_dates.push({'event_date' : val.event_date});
doSomething(val.event_date);
});
});
function doSomething(date) {
// do something with date
// like writing it to the page
// or displaying an alert
}
With this you'll be able to work with all the data you get as it becomes available.
Variables are global by default in Javascript - having var actually introduces scope. Remove that and see if it helps.
It's more likely that the AJAX response isn't returning any data. Can you try pushing just 'foo' onto the array, and see if the alert shows anything different?