QlikView Extensions – Avoiding Global Scope


QlikView Extension Objects allow a developer to create their own, custom objects in QlikView by using XHTML, CSS and JavaScript.  However, it is easy for an experienced QlikView developer – but inexperienced JavaScript developer – to get caught out by JavaScript’s “foibles” and spend several hours trying to figure out why their code isn’t working the way it should.  One such nuance of the JavaScript language has to do with the declaration of Functions and Variables – two of the fundamental building blocks of the language.

Functions

In some of the examples I’ve seen on the web, the callback function is declared before it is included in the AddExtension method eg.:

function myCallback() {
    ...//code here
}
Qva.AddExtension("HelloWorld", myCallback);

This is not good.  Doing so adds ‘myCallback’ to the global object (which is ‘window’, btw).  If you have multiple Extensions, each with their own function called ‘myCallback’, then each successive declaration blitzes the ‘myCallback’ declared before it with the result that only the last man standing will be used in all of your Qva.AddExtension invocations.  Furthermore, just which one will be used depends on the order in which the QlikView JavaScript engine chooses to compile them.  This order can change unpredictably thereby resulting in your Extensions behaving strangely.

You can, of course, choose to name your callback functions so that they don’t clash with any of your others but this doesn’t help someone else who uses your Extension and – by chance – already has a function declared with the same name.  Sure you could try ‘security by obscurity’ and give your functions GUIDs or something like that but, why bother?  It’s so much simpler to take the better route: define the function in the AddExtension definition:

Qva.AddExtension("HelloWorld", function() {
    ...//code here
});

Here we pass in an ‘anonymous function’ as our callback (‘anonymous’ because the function has no name – it’s just “function() {…}”) and, because we define the function within the enclosing AddExtension call, it is only ‘visible’ within the AddExtension method.  There is no pollution of the Global scope.

Variables

The same applies to variables.  I have seen:

var template_path = Qva.Remote + ...
Qva.AddExtension("HelloWorld", function() {
    Qva.LoadCSS(template_path + 'styles.css');
    ...//more code here
});

Again, ‘template_path’ is being defined on the Global object (window) and, accordingly, multiple Extensions using the same variable name, will blitz each other and you’ll be left scratching your head as to why your CSS doesn’t seem to work anymore.  It’s much better to:

Qva.AddExtension("HelloWorld", function() {
    var template_path = Qva.Remote + ...
    Qva.LoadCSS(template_path + 'styles.css');
    ...//more code here
});

Of course, don’t forget the ‘var’ prefix. If you do, you’ll be back to square one as using a variable without first declaring it results in that variable being defined on the Global object – waiting to be blitzed.  I’ve used ‘var’ in the above examples.  QlikView 11 and 12 support both ‘let’ and ‘const’ from ES6 so, you may opt to use those instead.  YMMW for earlier versions of QlikView (eg. 10).

To see what I mean, implement the following 4 extensions and compare their results:

var myPath = "hello myPath";
Qva.AddExtension("HelloWorld", function() {
    this.Element.innerHTML = myPath;
});

Qva.AddExtension("HelloWorld", function() {
    var myPath = "hello myPath";
    this.Element.innerHTML = myPath;
});

var myPath = "hello myPath";
Qva.AddExtension("HelloWorld", function() {
    this.Element.innerHTML = window.myPath;
});

Qva.AddExtension("HelloWorld", function() {
    myPath = "hello myPath";
    this.Element.innerHTML = window.myPath;
})

The 1st and 2nd give the expected behaviour and the 3rd and 4th match the 1st and 2nd respectively.  However, notice that in the 3rd and 4th we’re calling the myPath property of the window object (the Global object).  In the 3rd our variable was defined outside of the AddExtension function and in the 4th we used our variable without declaring it first (the ‘var’ prefix is missing).  Both situations resulted in myPath being added to the Global object and, thus, having Global scope.  Polluting the Global scope like this won’t necessarily lead to any problems – particularly if you never use the same variable/function name, but it is so easy to avoid taking this risk that you really have to question why you would choose to take it in the first place.  Hopefully, armed with above, you now know how to avoid it.

 

Categories:BI, JavaScript

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: