QlikView runs BodyOnLoadFunctionNames callbacks too early - why? - javascript

I have a problem with QlikView in the browser: I have a listbox and try to access it using an initialize script.
The script is registered by using the InitWorkbench function, using its BodyOnLoadFunctionNames parameter. So far, this works, and the initializer is run at startup.
Inside the initializer I try to do the following:
var doc = Qv.GetCurrentDocument();
var listbox = doc.GetObject('LB01');
Afterwards, when I have a look at listbox.Type, unfortunately it is undefined. If I delay execution of this query, it correctly says LB, hence apparently the query works - but only when it is executed delayed.
So, obviuosly there's a timing problem, and it seems as if the initializer runs too early (or I am doing something wrong).
Can anybody point out what the solution is (or give me a hint on what I am doing wrong)?

Okay, I've found the solution: The internal update function did not run yet, and all the values are only available once this function ran, so you need to provide a callback to the call to GetObject (that gets called after the update function):
var doc = Qv.GetCurrentDocument();
var listbox = doc.GetObject('LB01', function () {
console.log(listbox.Type); // => 'LB'
});

Related

Recommended way to Execute a function stored as String in JavaScript instead of using eval

Before anyone marks it as duplicate, this post does not actually answer the question but suggests a different way altogether to solve that particular issue.
Mine is a different issue. Please let me explain.
In my case, there are various .js files (plugins) which are being loaded with jquery getscript and stored in variables. Then whenever required they will be executed (more than once)
The code for loading script (this code will only run once at the init of the system for each plugin js file)
var storedFunc;
$.getScript(pathToPluginJSFile, function( data, textStatus, jqxhr ) {
storedFunc = data;
});
All the plugins are in this format
(function(){
//lots of code here
})()
But when I checked the storedFunc variable in console, I found out that it has been stored as String variable. Like this,
"(function(){
//lots of code here
})()"
Now to execute this, I used eval, like this (this code can be executed multiple times based on the need)
eval(storedFunc)
Everything is working fine and i am happy with it, but here comes the problem, I read in somewhere that the usage of eval is kind of like a bad thing to do. So now I am afraid that thought everything is working fine, all these negativity of using eval spread on the internet might scare my client away. :(
So, please tell me how I can run that stored function (which has become a string) without using eval.
Or should I use anything else than $.getScript which does not convert a function into a string ?
Or if there is any other way altogether rewriting this plugin functionality?
Please show me the way. I am in need of this solution badly.
Any help will be appreciated.
Thanks in advance.
Understanding how $.getScript works
Seems there is some confusion on how $.getScript works. If you notice jQuery's documentation on the method, and as #Pointy made mention of in the comments, this is stated:
Load a JavaScript file from the server using a GET HTTP request, then execute it.
Here's an example: Let's pretend the contents of the file being returned is only this:
// Contents of yourExternalFile.js
console.log('Executed!');
Now, when you use $.getScript:
$.getScript(pathToPluginJSFile, function( data, textStatus, jqxhr ) {
// The script you retrieved has already executed at this point, and you will find "Executed!" in the console.
console.log('All Done');
});
Console output:
> Executed!
> All Done
The $.getScript method is not meant to be used to return a string of the content of the file. However, while that data is available in the callback, the contents of the file have already been executed. So by taking the string version of the file, and re-executing it with either new Function, or even eval, you are executing it twice on the page (jQuery does it once, and so do you).
Original Post:
Use the Function constructor instead of using eval.
// Your function as a string stored to a variable
var stringFunction = "(function(){console.log('Executed');})()";
// Use the Function constructor to create a new function:
var executableFunction = new Function(stringFunction);
// Now you can execute it
executableFunction(); // logs "Executed"
This snippet from this SO question/answer addresses the difference between eval and new Function.
eval() evaluates a string as a JavaScript expression within the current execution scope and can access local variables.
new Function() parses the JavaScript code stored in a string into a function object, which can then be called. It cannot access local variables because the code runs in a separate scope.
Additional Information (Based on comments)
Yes, you can just get the string contents of the file and store them to a variable without the contents of the file executing. You can have that function to execute anytime. You just need to use the regular get method using jquery, and set the dataType to text. This way, the script will not execute, and you can execute it as you see fit:
var storedFunction;
$.get({url: pathToPluginJSFile, dataType: 'text'})
.done(function (data) {
// Turn the script into a new function and store it
// The information in the script file has not done anything yet
storedFunction = new Function(data);
})
.fail(function () {
console.log('Failed :(');
});
The only thing you will have to watch out for, is making sure that the function was assigned to the storedFunction variable as you are making an api call, and you have to wait for that to finish before attempting to make the function execute.
// Later on, call that function anytime, and as often as you want:
storedFunction();

Can't use variables outside of function in javascript

I recently started to learn Javascript and have prior experience in server side languages such as PHP. The issue I'm having is that I cannot use variables that are defined outside of a function inside the function. I always have to copy the variable into the function in order to get my code to work. I will post an example below.
var first = document.getElementById("first");
var second = document.getElementById("second");
function add () {
alert(Number(first.value) + Number(second.value));
}
Most likely the problem is that your script is being executed when the page is still being loaded, and before the "first" and "second" elements have been created.
Accessing the variables works fine. They just happen to be initialized to "undefined" at the time they are created. Moving the variables inside the function means that they aren't initialized until the function is called, which is after the page has been completely loaded.

Node.js vs Javascript Closure

I'm working my way through the Eloquent JavaScript Book and in it there is the following code:
function createFunction(){
var local = 100;
return function(){return local;};
}
When I run this via the node console (run node from command prompt) by calling createFunction(), I get [Function] as a returned value. However, according to the book I should get 100.
So my two questions: Why is this? and Second, is running these little examples in the node console a bad idea for testing JS code?
You need to call the response of createFunction().
createFunction()();
The first invocation (()) calls createFunction() and returns the inner function, which the second invocation executes and returns the local variable which was closed over.
Running small examples in a node console (or any other) is fine, so long as you know the environment, e.g. a browser's console is generally eval()'d, which can create side effects, such as how delete can apparently delete variables, not just object properties.
You get 100 by invoking the return value of createFunction, which is itself a function.
createFunction()();
...or perhaps more clearly...
var new_func = createFunction();
new_func();
function createFunction(){
var local = 100;
// v---v-----------------------v return a function from createFunction
return function(){return local;};
}
// v------- the returned function is assigned to the new_func variable
var new_func = createFunction();
// v------- the returned function is invoked
new_func();
For those that have a similar problem, I completely missed the double () so the call looks like createFunction()().

Javascript anonymous function not updating global variable

I've got a $.getJSON call in some code that appear to be not updating a global variable, and I'm at a loss to understand why. The JSON data is being loaded OK, but for some reason the global EventOptions array is not being updated in the for {} loop. The capitalised comments refer to the variable. Any ideas? Thanks
function LoadMeasurementTypes() {
// Clear out EventOptions
EventOptions = ["..."];
// Push a couple on to EventOptions - THESE ADD OK
EventOptions.push("Temperature");
EventOptions.push("Pulse rate");
// Call json to get measurementTypes off the table
$.getJSON('./get-measurement-types.php', function (measurementTypeData) {
// Process each json element ([0].BP, [1].ph (Urine) etc.
for (var i = 0; i < measurementTypeData.length; ++i) {
// e is a storage variable to contain the current element
var e = measurementTypeData[i];
// Add the new measurement type
alert(e.measure_type); // OK works - we can see the measure_type
EventOptions.push(e.measure_type); // THESE ARE NOT BEING ADDED
}
} // end anonymous function
) // end get json call
EventOptions.push("Last one"); // THIS ONE IS BEING ADDED
}
Your EventOptions[] is not globally visible. My guess would of been that it should still be visible locally to your $.getJSON call; but because it is now scoped to jquery, its clearly obscured (did you alert(EventOptions); inside your anon function to test?.
To properly scope, just declare it outside of LoadMeasureTypes().
var EventOptions = ["..."];
function LoadMeasureTypes(){...
-update
if this does not work - you could always pull the anonymous function outside of the $.getJSON() and assign it a variable name:
var retreiveTypes = function(){...};
$.getJSON("..path/php", retreiveTypes);
window.EventOptions = ["..."]
Good 'ol "hack" to put stuff in the global context
Got the answer: well kind of. It won't work on iTouch Safari, but is fine on Firefox (Mac). Bosworth I'm figuring it's a browser issue you noted above.
Interestingly, it may be something to do with threads. It appear the out loop runs before the inner anonymous loop has finished (the alerts are not in sequence!). I didn't think javascript used threads this way, but I may be wrong.
I now suspect the whole issue is a timing one - with a new thread as an anonymous function not completing in time.
Thanks guys.

Strange behavior on function calling

When calling a Javascript function, it seems like JS gives priority to functions without parameters first, even if I have the same function name with parameters.
The strange behavior only happens in the following scenario:
I have a an HTML page with embedded Javascript, like this:
//Javascript in the page
function testAbc(){
alert('testAbc no params');
}
//Javascript in common.js
function testAbc(x){
alert('testAbc with param:'+x);
}
function testAbcFunc(x){
testAbc(x);
}
Now from somewhere in the page, im calling testAbcFunc from the common.js expecting it to call testAbc with parameter which is the common function. But strangely, JS calls back the function in the original page without params!!
I have been debugging this bug fore few hours now, and i tried this short code to reproduce the bug, it does happen each time.
NOTE: if all functions are in the same page, the correct function (with params) will be called, but when ther are split between the page and the JS file. JS seems to give priority to the function in the page even though is doesn't have parameter
JavaScript does not support method overloading based on parameters. It simply uses the last-defined function if multiple functions have the same name. The version in the page will override the included version. When it worked for you, I assume that the include version (with the argument signature) was inlined after the original.
JavaScript doesn't have overloaded function. It doesn't care about signatures, it calls functions solely by names and nothing else. It is strange that later function does not completely hide the first one but well, there's no spec about that behaviour.
So just don't do that, check the number of params with arguments.length inside the function and don't try to use overloading which will never work.
function testAbc(){
if (arguments.length == 0) {
alert('testAbc no params');
} else {
var x = arguments[0];
alert('testAbc with param:'+x);
}
}
There is no function overloading in JavaScript. If you are defining a function with two times with diffrent number of parameters the last one to be defined will be called.
Also, you should be namespacing your JavaScript.
Like so:
var common = {
testABC: function () {
//Stuff
}
};
Then call testABC like this
common.testABC();

Categories