JavaScript function returns undefined except when debugging - javascript

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.

Related

jQuery html() doesn't complete

I have a utility function to insert HTML into a div and then call a javascript initializer function that attaches event handlers to various elements in the inserted HTML. The functions works great for 90% of cases but periodically fails in the jquery html() call below. When it fails, the HTML is inserted properly but the code on the next line is never reached.
function loadSection(id, url, initializer = null, param = null) {
const $div = $('#' + id);
return $.ajax({
method: 'GET',
url: url,
})
.done(function (html) {
$div.html(html);
if (initializer) { // This line is never reached.
initializer(param);
}
});
}
The same failure occurs if I use $div.empty().append(html) instead of $div.html(html) so the problem isn't in the html() function itself. In fact, if I step through the html() code, it executes this.empty().append(value) and never returns to the calling function.
The html that is inserted may contain to set variable values but does not call any javascript functions directly.
I've done a pretty exhaustive search of StackOverflow and the web but have come up empty. I've also traced through the jQuery code but couldn't identify the issue. Can anyone tell me why this is failing?
Answers to some of the questions:
It IS deterministic. The failure cases always fail and vice versa.
I know the code succeeded because code execution gets to $div.html(html). And the html returned in the GET is correct.
Example of how this is called:
function loadNewContracts() {
loadSection('prospector-newContracts', '../newContracts', initNewContracts);
}
The initializers are different for every section. The key points is that the initializer is NEVER called.
The correct initializer IS being passed into the function and does exist.
The only tags in the HTML set variable values. No js functions are called. Calls that succeed also set variable values. There are NO loops in the tags.
The $div variable DOES exist in all cases.
Barmar was close and gave me the idea to figure this one out. The js variables being set in the html are generated in a jinja2 template. A non-existent value was being passed to the template so the script ended up looking like ...
var currentValue = ;
... so the js fails while loading the html. Another one failed in an similar manner. These failed because of recently introduced bug in the server code.
Obvious in retrospect but I overlooked it because you can't break on the js in the . Thanks, Barmar!

How to use JSONP with Object Oriented Javascript

I am new to JSONP and had implemented cross domain functionality for my application and everything is working fine. Now i want to change my javascript code to apply object orientation.
My api is
http://localhost:8080/myApplication/getComments?callback=displayComments
CrossDomain.prototype.displayComments = function(data) {
// code to display the comments
}
Now I am getting an error in firebug given below
ReferenceError: displayComments is not defined
I changed the api to
http://localhost:8080/myApplication/getComments?callback=this.displayComments
and found that the function is appended inline to the callback like this
http://localhost:8080/myApplication/getComments?callback=callback=function (jsonData)
{
//code to display the comments
}
this time another error in firebug
SyntaxError: function statement requires a name
I have a doubt whether to use JSONP in object oriented javascript or not.
Please help.
Thanks in advance.
There's no point in defining the function on the prototype of a function unless you are going to create instances of that function, so start by doing that.
var myCrossDomain = new CrossDomain();
Then you have to call the method on the object, not as a global (it isn't a global, so you can't do that anyway)
var uri = "http://localhost:8080/myApplication/getComments?callback=" +
encodeURIComponent("myCrossDomain.displayComments");
In response to edits and comments:
Yes i am creating an instance of this in another js file
Then reference it as shown above.
I changed the api to
http://localhost:8080/myApplication/getComments?callback=this.displayComments
It's JSON-P. It runs by adding a new script element. Everything gets called in the global context. That is going to call this.displayComments which will be the same as window.displayComments.
If you want to call your method directly, then you need to specify the global variable holding the instance explicitly.
If you don't want to call it directly then you can use the more traditional approach of generating a new, anonymous function which has access to said object through a closure, assigning that function to a global variable (with a unique name) and using that name as your callback argument.
and found that the function is appended inline to the callback like this
http://localhost:8080/myApplication/getComments?callback=callback=function (jsonData)
You haven't shown us the code that creates the URI so we can't tell why that might be the case.

Why in JavaScript is necessary to pass an argument even if it's not going to be used inside the function?

Not sure if this is a dumb question. I've started playing with a few JavaScript frameworks and I always get confused when I see an argument that is not being used inside a function.
A Backbone example (the model arg):
var Todo = Backbone.Model.extend({
validate: function(attribs){
if(attribs.title === undefined){
return "Title can't be undefined";
}
},
initialize: function(){
console.log('This model has been initialized');
this.on('error', function(model, error){
console.log(error);
});
},
});
Express example (the req and next args):
app.use(function(err, req, res, next){
console.error(err.stack);
res.send(500, 'Something broke!');
});
So, I'm wondering, those values are just ignored? What would happen if you leave them out? And why they have to be included in the first place? (I'm used to the idea that if a function passes an argument is because it will be used in the function).
In the case of initialize:
The variable model isn't used, but error is. Because error is the 2nd argument, model must be passed as a place holder.
The same thing is true in use:
The variable req isn't used, but it is required as a place holder so res can be used.
Why do the functions have parameters that don't appear to be used?
Maybe it's for backwards compatibility or for extensibility.
I assume these are both open source libraries (I've never used either).
If those values are ignored, nothing would happen and it would work good as well.
Whether those values are ignored or not, whether you use them or not, they are passed in actually.
You dont have to, unless you are using an argument that is after the an argument you dont use.
And even then , you could use the argument object in a function to get the argument at the right index.
function myFunc(){
console.log(arguments);
}
myFunc(1,2,3,4,5,6); // logs 1,2,3,4,5,6
In a documentation , though , it is better to let the developper know what arguments are injected in the callback so the developper can have a clear view of the continuation configuration.
You are correct that these arguments will be ignored if you do not use them. Also, they can be safely left out. But, if you only want to access the second argument you will need to have the first there as a placeholder.
As to why these arguments are there? It is important to understand that what you are passing in is a callback function. This callback is then called at a later point by the function that you passed it into. So it is the function provided by the framework that is calling your callback function and passing in these arguments. The Framework has no way of knowing what your specific use case is and has know way of knowing exactly what data your callback needs. Thus the authors of the framework pass in several arguments with enough data to cover as many use case as possible. While your callback function is not making use of these arguments other developers using these frameworks might be writing a callback that does.

Lawnchair javascript data "get" does not let me assign into another variable

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

Pass a callback in ExternalInterface

I want to call a Javascript function from Flash, which I can do with ExternalInterface, but the Javascript function takes a callback. Is there a way to give it a Flash callback?
I've thought of something like this:
ExternalInterface.addCallback("foo", function(){...});
ExternalInterface.call("theFunction", "foo");
But that wouldn't work since theFunction would attempt to do foo(), while it should really do swfObject.foo(). The problem is the page and its Javascript are not under my control (though I can request changes if really needed).
This is closely related to the first question in the related questions section.
Along the same lines as the answer to that question, you can do:
ExternalInterface.addCallback("foo", function() { /* ... */ }); // The callback
ExternalInterface.call("theFunction(function() { swfObject.foo(); })");
You're misunderstanding the documentation, I think. callback in this instance is just a reference to a function inside Flash, not a callback to something you call.
Basically, you use .call() to call a JS function from AS; and you use .addCallback() to tell the Flash Player which AS function should be called based on the name.
On your example, theFunction would get one parameter as being 'foo', which is the name that references your anonymous AS function. Not sure why you would want to pass the function like that, but if you need, you could just call it from JavaScript with
function theFunction(callback) {
// .. do something...
swfObject[callback]();
}
Now, if you don't have control over the JS/HTML side, I'm not sure if you can do that. Not sure why you'd need, anyway - JS calls are synchronous, as if they were running on the same thread, meaning the Flash Player will execute the JS code and only then return to the Flash Player... you don't have to wait for execution or anything.
Also, if you really need to control the page without touching the JS/HTML side, remember you can inject entire pieces of JS code via .call - it doesn't need to be a simple function call. You can create your entire functions from inside the SWF. For example,
var js:XML = <script><![CDATA[
// Javascript code...
]]></script>;
ExternalInterface.call(js);
Or, if you need the return data, you don't need a callback either - just do a simple call as in
// JS
function isNumberZero(__num) {
return __num == 0;
}
// AS
trace ("Is number zero = " + ExternalInterface.call("isNumberZero", 10));
Not sure if this helps at all. If not, it'd be good to have more information on what exactly you're trying to do.

Categories

Resources